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