在 上一篇 中讲到了在 NetCore 项目中如何配置 NLog 将日志存到数据库, 这篇中将讲述如何处理自定义抛出的异常以及未处理的异常, 并通过日志记录下来.
为什么要进行异常的全局处理和记录日志呢?
在实际的软件项目开发与迭代中, 无论程序员是久经沙场的老将, 还是初出茅庐的萌新, 出现异常 (尤其是空指针异常) 是必然的,
一般来说, 当出现异常且没有处理的情况下, 异常会直接抛至运行环境, 导致系统崩溃或其它错误, 那么如何才能做到系统在运行时遇到错误而不致使系统崩溃呢, 需要在系统出现未捕捉的异常时进行全局处理并记录以方便修复!
在程序中, 在某些地方可能需要手动抛出异常, 需要自定义消息等等, 因此, 我们先添加自定义异常类 CustomSystemException .
- /// <inheritdoc />
- /// <summary>
- /// 自定义系统错误异常
- /// </summary>
- public class CustomSystemException : Exception
- {
- /// <summary>
- /// HTTP 状态码
- /// </summary>
- public int Code { get; set; }
- /// <summary>
- /// 错误消息
- /// </summary>
- public object[] Args { get; set; }
- public CustomSystemException(string message, int code, params object[] args) : base(message)
- {
- Code = code;
- Args = args;
- }
- }
在 NetCore 中有一个 ExceptionFilterAttribute 的异常过滤属性, 可以继承它来重写当触发时的事件.
- /// <inheritdoc />
- /// <summary>
- /// 全局异常处理过滤器
- /// </summary>
- public class ExceptionFilter : ExceptionFilterAttribute
- {
- public override void OnException(ExceptionContext filterContext)
- {
- if (filterContext.ExceptionHandled)
- return;
- var controllerName = (string)filterContext.RouteData.Values["controller"];
- var actionName = (string)filterContext.RouteData.Values["action"];
- var request = filterContext.HttpContext.Request;
- LogHelper.Logger.Fatal(filterContext.Exception,
- $"[异常信息] :{filterContext.Exception.Message} [请求路径] :{request.Method}:{request.Path}\n" +
- $"[控制器] :{controllerName} - [方法] :{actionName}\n" +
- $"[主机地址] :{ Demoweb.GetClientIp()}" +
- $"[用户代理] :{ request.Headers["User-Agent"]}");//DemoWeb 为前面章节添加的类
- if (filterContext.Exception is CustomSystemException se)
- {
- filterContext.Result = new CustomHttpStatusCodeResult(200, se.Code, se.Message);
- }
- else
- {
- #if DEBUG
- Console.WriteLine(filterContext.Exception);
- var content = filterContext.Exception.ToJson();//ToJson 为静态扩展方法 为前面章节添加的类
- #else
- var content = "系统错误, 请稍后再试或联系系统管理人员.";
- #endif
- filterContext.Result = new CustomHttpStatusCodeResult(200, 500, content);//CustomHttpStatusCodeResult 为自定义返回结果 为前面章节添加的类
- }
- filterContext.ExceptionHandled = true;
- }
- }
其中涉及到的在前面章节都有添加, 统一返回结果以及静态方法等.
这里添加好了之后, 我们需要将这个过滤器注入到 MVC 中去, 在 Startup 类中的 ConfigureServices 方法 中做如下更改:
- services.AddMvc(options =>
- {
- options.Filters.Add(new ExceptionFilter());
- }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
- // 用上面的替换下面的
- //services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
到这里, 添加完了全局异常处理, 然后在控制器层添加一个测试方法, 测试代码如下: PS: 若启动访问不到测试接口, 请在启动项目中添加该控制器类库的引用!
- [Route("api/[controller]")]
- public class ExceptionTestController : BaseController
- {
- [HttpGet]
- [Route("dividezero")]
- public ActionResult TestDivideZero()
- {
- LogHelper.Logger.Debug("测试除 0 异常");
- var zero = 0;
- var test = 10 / zero;
- return Succeed();
- }
- }
测试效果如下:
个人建议: 不要用太多的异常处理, 也最好不要进行手动抛出异常处理, 能规避的异常和能处理的异常建议都进行处理并返回提示信息, 同时要尽量避免使用套嵌异常处理, 因为异常处理使用不合理会使系统的性能下降.
在下一篇中将介绍如何使用过滤器来进行模型验证处理, 验证请求数据是否符合访问模型设置的要求, 并返回错误提示信息.
有需要源码的在下方评论或私信~ 给我的 SVN 访客账户密码下载, 代码未放在 GitHub 上.
来源: https://www.cnblogs.com/levywang/p/coreframe_5.html