ASP.NET Core 6.0 使用 ExceptionFilter

ExceptionFilter 扩展

同步异常的执行特点:
如果实现ActionFilterAttribute抽象父类,在执行的时候,只会执行异步版本的方法(在源码中他是直接判断了,如果有异步版本,同步版本就不执行了)。

CustomExceptionFilterAttribute 同时实现 IExceptionFilter 和 IAsyncExceptionFilter,会使用 OnExceptionAsync 异步方法。

    public class CustomExceptionFilterAttribute : Attribute, IExceptionFilter,IAsyncExceptionFilter
    {
        /// <summary>
        /// 当有异常发生的时候,就会触发到这里
        /// </summary>
        /// <param name="context"></param>
        /// <exception cref="NotImplementedException"></exception>
        public void OnException(ExceptionContext context)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 当有异常发生的时候,就会触发到这里
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public Task OnExceptionAsync(ExceptionContext context)
        {
            throw new NotImplementedException();
        }
    }
        #region ExceptionFilter
        [CustomExceptionFilter]
        public IActionResult Index7()
        {
            throw new Exception("测试,抛出一个异常");
        }
        #endregion

ExceptionFilter封装扩展

异常的标准处理方式

    public class CustomExceptionFilterAttribute : Attribute, IExceptionFilter,IAsyncExceptionFilter
    {
        private readonly IModelMetadataProvider _IModelMetadataProvider;
        public CustomExceptionFilterAttribute(IModelMetadataProvider modelMetadataProvider)
        {
            this._IModelMetadataProvider = modelMetadataProvider;
        }

        /// <summary>
        /// 当有异常发生的时候,就会触发到这里
        /// </summary>
        /// <param name="context"></param>
        /// <exception cref="NotImplementedException"></exception>
        public void OnException(ExceptionContext context)
        {
            if (context.ExceptionHandled == false)
            {
                //在这里就开始处理异常--还是要响应结果给客户端
                //1.页面展示
                //2.包装成一个JSON格式
                if (IsAjaxRequest(context.HttpContext.Request)) //判断是否是Ajax请求--JSON
                {
                    //JSON返回
                    context.Result = new JsonResult(new
                    {
                        Succeess = false,
                        Message = context.Exception.Message
                    });
                }
                else
                {
                    //返回页面
                    ViewResult result = new ViewResult { ViewName = "~/Views/Shared/Error.cshtml" };
                    result.ViewData = new ViewDataDictionary(_IModelMetadataProvider, context.ModelState);
                    result.ViewData.Add("Exception", context.Exception);
                    context.Result = result; //断路器---只要对Result赋值--就不继续往后了; 
                }
                context.ExceptionHandled = true;//表示当前异常被处理过
            }
        }

        /// <summary>
        /// 当有异常发生的时候,就会触发到这里
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public Task OnExceptionAsync(ExceptionContext context)
        {
            throw new NotImplementedException();
        }

        private bool IsAjaxRequest(HttpRequest request)
        {
            //HttpWebRequest httpWebRequest = null;
            //httpWebRequest.Headers.Add("X-Requested-With", "XMLHttpRequest"); 
            string header = request.Headers["X-Requested-With"];
            return "XMLHttpRequest".Equals(header);
        }

    }
        #region ExceptionFilter
        [TypeFilter(typeof(CustomExceptionFilterAttribute))]
        public IActionResult Index7()
        {
            throw new Exception("测试,抛出一个异常");
        }
        #endregion
@model ErrorViewModel
@{
    Exception exception = ViewData["Exception"] as Exception;
}

<h1 class="text-danger">Error.</h1>
@if (exception != null)
{
    <h3 class="text-danger">exception.Message</h3>
}

ExceptionFilter覆盖范围

Action出现没有处理的异常

        /// <summary>
        /// Action出现没有处理的异常
        /// </summary>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        [TypeFilter(typeof(CustomExceptionFilterAttribute))]
        public IActionResult Index8()
        { 
            throw new Exception(" Action出现没有处理的异常");
        }

Action出现已经处理的异常

        /// <summary>
        /// Action出现已经处理的异常
        /// </summary>
        /// <returns></returns>
        [TypeFilter(typeof(CustomExceptionFilterAttribute))]
        public IActionResult Index9()
        {
            try
            {
                throw new Exception(" Action出现已经处理的异常");
            }
            catch (Exception)
            {
                return View();
            }
        }
@{
    ViewData["Title"] = "Index4";
}

<h1>Third-Index9</h1>

Service层的异常

可以捕获异常 

        /// <summary>
        /// Service层的异常
        /// </summary>
        /// <returns></returns>
        [TypeFilter(typeof(CustomExceptionFilterAttribute))]
        public IActionResult Index10()
        {
            new ExceptionInFoService().Show();
            return View();
        }
    public class ExceptionInFoService
    {
        public void Show()
        {
            throw new Exception("Service层的异常     ");
        }
    }


View绑定时出现了异常 

        /// <summary>
        /// View绑定时出现了异常
        /// </summary>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        [TypeFilter(typeof(CustomExceptionFilterAttribute))]
        public IActionResult Index11()
        {
            return View();
        }

这里出现的异常是捕捉不到的 

@{
    ViewData["Title"] = "Index3";
}

@{
    throw new Exception("View 绑定的时候发生异常");
}

<h1>Third-Index11</h1>


不存在的Url地址

捕捉不到异常


其他Filter中发生的异常

如果在 Action过滤器发生异常,CustomExceptionFilterAttribute可以捕获,Resource过滤器 和Result过滤器发生异常时, CustomExceptionFilterAttribute可以捕获不到。

        /// <summary>
        ///其他Filter中发生的异常
        /// </summary>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>

        [TypeFilter(typeof(CustomExceptionFilterAttribute))]
     /*  [TypeFilter(typeof(CustomLogActionFilterAttribute))] */  //Action中发生异常---可以捕捉到
       // [TypeFilter(typeof(CustomCacheResourceFilterAttribute))]   //Resource中发生异常--捕捉不到
        [TypeFilter(typeof(CustomResultFilterAttribute))]   //Result中发生异常 ---捕捉不到的
        public IActionResult Index12()
        {
            return View();
        }


控制器构造函数出现异常

可以捕捉到异常

ExceptionFilter未捕捉到的异常处理

中间件支持

综合支持可以捕捉到所有的异常
ExceptionFilter+中间件==处理所有的异常

#region 中间件处理异常
{
    ///如果Http请求中的Response中的状态不是200,就会进入Home/Error中;
    app.UseStatusCodePagesWithReExecute("/Home/Error/{0}");//只要不是200 都能进来

    //下面这个是自己拼装一个Reponse 输出
    app.UseExceptionHandler(errorApp =>
    {
        errorApp.Run(async context =>
        {
            context.Response.StatusCode = 200;
            context.Response.ContentType = "text/html";
            await context.Response.WriteAsync("<html lang=\"en\"><body>\r\n");
            await context.Response.WriteAsync("ERROR!<br><br>\r\n");
            var exceptionHandlerPathFeature =
                context.Features.Get<IExceptionHandlerPathFeature>();

            Console.WriteLine("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
            Console.WriteLine($"{exceptionHandlerPathFeature?.Error.Message}");
            Console.WriteLine("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");

            if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
            {
                await context.Response.WriteAsync("File error thrown!<br><br>\r\n");
            }
            await context.Response.WriteAsync("<a href=\"/\">Home</a><br>\r\n");
            await context.Response.WriteAsync("</body></html>\r\n");
            await context.Response.WriteAsync(new string(' ', 512)); // IE padding
        });
    });
}
#endregion
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夜飞鼠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值