Asp.Net Core中5种异常处理方案

作者 the7
发布于 2020年02月13日
评论 0
浏览 145

异常处理在编程中非常重要,一来可以给用户友好提示,二来也是为了程序安全。在Asp.Net Core中,默认已经为我们了提供很多解决方案,下面就来总结一下。

一,继承Controller,重写OnActionExecuted

使用vs新建controller时,默认都会继承一个Controller类,重写OnActionExecuted,添加上异常处理即可。一般情况下我们会新建一个BaseController, 让所有Controller继承BaseController。代码如下

public class BaseController : Controller
{
    public override void OnActionExecuted(ActionExecutedContext context)
    {
        var exception = context.Exception;
        if (exception != null)
        {
            context.ExceptionHandled = true;
            context.Result = new ContentResult
            {
                Content = $"BaseController错误 : { exception.Message }"
            };
        }
        base.OnActionExecuted(context);
    }
}

这种处理方式优点当然是简单,缺点也很明显,如果cshtml页面抛错,就完全捕获不了。当然如果项目本身就是一个web api 项目,没有view,这还是可以的。

二,使用 ActionFilterAttribute

ActionFilterAttribute是一个特性,本身实现了 IActionFilterIResultFilter , 所以不管是action里抛错,还是view里抛错,理论上都可以捕获。我们新建一个 ExceptionActionFilterAttribute, 重写 OnActionExecutedOnResultExecuted,添加上异常处理,完整代码如下。

public class ExceptionActionFilterAttribute:ActionFilterAttribute
{
    public override void OnActionExecuted(ActionExecutedContext context)
    {
        var exception = context.Exception;
        if (exception != null)
        {
            context.ExceptionHandled = true;
            context.Result = new ContentResult
            {
                Content = $"错误 : { exception.Message }"
            };
        }
        base.OnActionExecuted(context);
    }

    public override void OnResultExecuted(ResultExecutedContext context)
    {
        var exception = context.Exception;
        if (exception != null)
        {
            context.ExceptionHandled = true;
            context.HttpContext.Response.WriteAsync($"错误 : {exception.Message}");
        }
        base.OnResultExecuted(context);
    }
}

使用方式有两种,

  1. 在controller里打上 [TypeFilter(typeof(ExceptionActionFilter)] 标签。
  2. 在Startup里以filter方式全局注入。
    services.AddControllersWithViews(options =>
    {
        options.Filters.Add<ExceptionActionFilterAttribute>();
    })
    

三,使用 IExceptionFilter

我们知道, Asp.Net Core提供了5类filter, IExceptionFilter是其中之一,顾名思义,这就是用来处理异常的。Asp.net Core中ExceptionFilterAttribute已经实现了IExceptionFilter,所以我们只需继承ExceptionFilterAttribute,重写其中方法即可。 同样新建CustomExceptionFilterAttribute继承 ExceptionFilterAttribute,重写 OnException ,添加异常处理,完整代码如下

public class CustomExceptionFilterAttribute : ExceptionFilterAttribute
{
    public override void OnException(ExceptionContext context)
    {
        context.ExceptionHandled = true;
        context.HttpContext.Response.WriteAsync($"CustomExceptionFilterAttribute错误:{context.Exception.Message}");
        base.OnException(context);
    }
}

注意,ExceptionFilterAttribute还提供了异步方法OnExceptionAsync,这两个处理方法,只需重写一个即可,如果两个都重写,两个方法都会执行一次。

使用方式有两种,

  1. 在controller里打上 [CustomExceptionFilter] 标签。
  2. 在Startup里以filter方式全局注入。
    services.AddControllersWithViews(options =>
    {
        options.Filters.Add<CustomExceptionFilterAttribute>();
    })
    

四,使用ExceptionHandler

在 startup 里,vs新建的项目会默认加上

if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler("/Home/Error");
}

上边这段代码,大意为:开发环境使用app.UseDeveloperExceptionPage(); 。生产环境会跳转至 home/error 页面。
UseDeveloperExceptionPage 会给出具体错误信息,具体包括 Stack trace、Query、Cookies、Headers 四部分。.net core 3.1后有些改动,如果请求头加上 accept:text/html, 就返回html页面,不加的话,只会返回错误。

注意:app.UseDeveloperExceptionPage(); 应该置于最前边。

   if (!env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler(builder =>
        {
            builder.Run(async context =>
            {
                var exceptionHandlerPathFeature = context.Features.Get<IExceptionHandlerPathFeature>();
                await context.Response.WriteAsync($"error:{exceptionHandlerPathFeature.Error.Message}");
            });
        });
    }

五,自定义Middleare处理

通过middleware全局处理。

public class ErrorHandlingMiddleware
{
   private readonly RequestDelegate next;

   public ErrorHandlingMiddleware(RequestDelegate next)
   {
        this.next = next;
   }

   public async Task Invoke(HttpContext context)
   {
        try
        {
           await next(context);
        }
        catch (System.Exception ex)
        {
           //处理异常
        }
   }
}

4条评论

  • 念往昔丶繁华竞逐

    2019年5月20日

    最后一个五官很漂亮,虽然脸稍微大了一点点,但也算普通人里漂亮的
  • Eleven

    2019年5月20日

    念往昔丶繁华竞逐:
    最后一个五官很漂亮,虽然脸稍微大了一点点,但也算普通人里漂亮的...
    这帖子真的是精品。美中不足的是,为什么要用繁体,虽然能看懂,但有些麻烦呀。
  • SukiU

    2019年5月20日

    我曾在某外企互联网公司工作过一段时间,他们就是那种工作时间聊天摸鱼,下班时间拼命工作,然后加班蹭加班费和补贴😂
微信公众号
站长帮
微信公众号,每日更新!