一、ASP.NETCore提供的记录全局异常的几种方式
1、MVC框架-异常处理页(开发环境/生产环境)
1)开发环境
使用app.UseDeveloperExceptionPage()启用“异常处理页”;异常处理页显示真实的报错信息不可轻易让用户看到,一般在开发环境中使用。
builder.Services.AddControllers(); // 使用控制器
builder.Services.AddMvc(); // 使用MVC
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage(); // MVC开发环境下的异常处理页;WebAPI中不需要用,只使用SwaggerUI即可。
}
...
app.MapControllers();
app.Run();
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
2)生产环境
使用app.UseExceptionHandler("/error")自定义“异常处理页”;一般用在生产环境中。
builder.Services.AddControllers(); // 使用控制器
builder.Services.AddMvc(); // 使用MVC
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment()) // 开发环境下
{
app.UseDeveloperExceptionPage(); // MVC开发环境下的异常处理页;WebAPI中不需要用,只使用SwaggerUI即可。
}
else // IsProduction、IsStaging等环境下
{
app.UseExceptionHandler("/error"); // MVC开发环境下的自定义的异常处理页(页面为/error);保证返回信息中不包含敏感信息;WebAPI中不需要用,使用异常中间件即可。
}
...
app.MapControllers();
app.Run();
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
MVC视图(error)
@model fly_chat1_net7.Exceptions.IKnownException_UseExceptionHandler
@{
ViewData["Title"] = "Index";
}
<h1>错误信息</h1>
<div>发生错误的时间:<label>@Model.ErrorDateTime</label></div>
<!-- 错误信息也可以作为敏感信息,不做展示 -->
<div>错误信息:<label>@Model.ErrorMessage</label></div>
<div>错误代码:<label>@Model.ErrorCode</label></div>
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
MVC控制器(error)
using fly_chat1_net7.Exceptions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Mvc;
namespace fly_chat1_net7.Controllers
{
/// <summary>
/// MVC展示用户自定义异常信息页(KnownException_UseExceptionHandler)
/// </summary>
[AllowAnonymous]
public class ErrorController : Controller
{
/// <summary>
/// MVC展示用户自定义异常信息页(KnownException_UseExceptionHandler)
/// </summary>
/// <returns>返回用户自定义的Error信息</returns>
[Route("/error")]
public IActionResult Index()
{
// 获取当前上下文里面报出的异常信息
var exceptionHandlerPathFeature = HttpContext.Features.Get<IExceptionHandlerPathFeature>();
var ex = exceptionHandlerPathFeature?.Error;
// 特殊处理,尝试转换为 IKnownException
var knownException = ex as IKnownException_UseExceptionHandler;
// 对于未知异常,我们并不应该把错误异常完整地输出给客户端,而是应该定义一个特殊的信息 Unknown 传递给用户
// Unknown 其实也是一个 IKnownException 的实现,它的 Message = "未知错误", ErrorCode = 9999
// 也就是说我们在控制器 throw new Exception("报个错"); 就会看到错误信息
if (knownException == null)
{
knownException = KnownException_UseExceptionHandler.UnKnownException;
}
else// 当识别到异常是已知的业务异常时,输出已知的异常,包括异常消息,错误状态码和错误信息,就是在 IKnownException 中的定义
{
knownException = KnownException_UseExceptionHandler.SetKnownException(knownException);
}
return View(knownException);
}
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
MVC实体(error)
namespace fly_chat1_net7.Exceptions
{
/// <summary>
/// 自定义异常处理页接口_UseExceptionHandler
/// </summary>
public interface IKnownException_UseExceptionHandler
{
/// <summary>
/// 异常发生的时间
/// </summary>
public DateTime ErrorDateTime { get; }
/// <summary>
/// 异常信息(错误信息也可以作为敏感信息,不做展示)
/// </summary>
public string ErrorMessage { get; }
/// <summary>
/// 异常代码
/// </summary>
public int ErrorCode { get; }
/// <summary>
/// 异常对象
/// </summary>
public object[] ErrorData { get; }
}
/// <summary>
/// 自定义异常处理页_UseExceptionHandler
/// </summary>
public class KnownException_UseExceptionHandler : IKnownException_UseExceptionHandler
{
#region 变量
/// <summary>
/// 异常发生的时间
/// </summary>
public DateTime ErrorDateTime { get; private set; }
/// <summary>
/// 异常信息
/// </summary>
public string ErrorMessage { get; private set; }
/// <summary>
/// 异常代码
/// </summary>
public int ErrorCode { get; private set; }
/// <summary>
/// 异常对象
/// </summary>
public object[] ErrorData { get; private set; }
#endregion 变量
/// <summary>
/// 未知错误信息实体
/// </summary>
public readonly static IKnownException_UseExceptionHandler UnKnownException = new KnownException_UseExceptionHandler { ErrorDateTime = DateTime.Now, ErrorMessage = "未知错误", ErrorCode = 9999, ErrorData = null };
/// <summary>
/// 设置“自定义异常处理页”的内容
/// </summary>
/// <param name="exception">“自定义异常处理页”的内容</param>
/// <returns></returns>
public static IKnownException_UseExceptionHandler SetKnownException(IKnownException_UseExceptionHandler exception)
{
return new KnownException_UseExceptionHandler { ErrorDateTime = exception.ErrorDateTime, ErrorMessage = exception.ErrorMessage, ErrorCode = exception.ErrorCode, ErrorData = exception.ErrorData };
}
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
效果类似于下图:
2、异常过滤器 IExceptionFilter
实现 IExceptionFilter 或 IAsyncExceptionFilter,
可用于实现常见的错误处理策略(如:处理 Razor 页面或控制器创建、 模型绑定、操作筛选器或操作方法中发生的未经处理的异常)。但是,请不要捕获资源筛选器、结果筛选器或 MVC 结果执行中发生的异常。
ExceptionFilterAttribute)那么灵活。
1)实现 IExceptionFilter
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
namespace fly_chat1_net7.Middlewares
{
/// <summary>
/// 异常过滤器(筛选器)
/// 可用于实现常见的错误处理策略(如:处理 Razor 页面或控制器创建、模型绑定、操作筛选器或操作方法中发生的未经处理的异常)。
/// 但是,请不要捕获资源筛选器、结果筛选器或 MVC 结果执行中发生的异常。
/// 建议使用中间件处理异常。 基于所调用的操作方法,仅当错误处理不同时,才使用异常筛选器。
/// </summary>
public class SampleExceptionFilter : IExceptionFilter
{
#region 微软官方示例
//private readonly IHostEnvironment _hostEnvironment;
//public SampleExceptionFilter(IHostEnvironment hostEnvironment) =>
// _hostEnvironment = hostEnvironment;
//public void OnException(ExceptionContext context)
//{
// if (!_hostEnvironment.IsDevelopment())
// {
// // Don't display exception details unless running in Development.
// return;
// }
// context.Result = new ContentResult
// {
// Content = context.Exception.ToString()
// };
//}
#endregion 微软官方示例
/// <summary>
/// 实现OnException方法
/// </summary>
/// <param name="context">异常内容</param>
public void OnException(ExceptionContext context)
{
if (context.ExceptionHandled == false) // 如果异常没有被处理则进行处理
{
// 写自己的记录日志的方法
//_loggerHelper.Error(context.HttpContext.Request.Path, context.Exception);
context.Result = new ContentResult
{
// 返回状态码设置为200,表示成功
StatusCode = StatusCodes.Status200OK,
ContentType = "application/json;charset=utf-8", // 设置返回格式
Content = $"{{\r\n \"Code\": 500,\r\n \"Message\": \"{context.Exception.ToString()}\"\r\n}}\r\n"
};
}
context.ExceptionHandled = true; // 设置为true,表示异常已经被处理了
}
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
2)注册全局使用
3)WebAPI测试:
3、异常属性标识 ExceptionFilterAttribute(推荐)
ExceptionFilterAttribute
继承IExceptionFilter
。但可以获取比IExceptionFilter
更多的异常。建议使用中间件处理异常。 基于所调用的操作方法,仅当错误处理不同时,才使用异常筛选器。
1)重写 ExceptionFilterAttribute的OnException方法
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Newtonsoft.Json;
namespace fly_chat1_net7.Middlewares
{
/// <summary>
/// 全局异常中间件(使用ExceptionFilterAttribute属性标识)
/// ExceptionFilterAttribute继承IExceptionFilter。但可以获取比IExceptionFilter更多的异常。建议使用中间件处理异常。 基于所调用的操作方法,仅当错误处理不同时,才使用异常筛选器。
/// </summary>
public class MyExceptionFilter: ExceptionFilterAttribute
{
/// <summary>
/// 重写OnException方法
/// </summary>
/// <param name="context"></param>
public override void OnException(ExceptionContext context)
{
if (context.ExceptionHandled == false) // 如果异常没有被处理则进行处理
{
// 写入日志
//_loggerHelper.Error(context.HttpContext.Request.Path, context.Exception);
context.Result = new ContentResult
{
// 返回状态码设置为200,表示成功
StatusCode = StatusCodes.Status200OK,
ContentType = "application/json;charset=utf-8", // 设置返回格式
Content = $"{{\r\n \"Code\": 500,\r\n \"Message\": \"{context.Exception.ToString()}\"\r\n}}\r\n"
};
}
context.ExceptionHandled = true; // 设置为true,表示异常已经被处理了
}
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
2)注册全局使用
3)WebAPI测试:
4、异常处理-UseExceptionHandler()+委托方法(不推荐)
略
作者:꧁执笔小白꧂