Why choose exception handling middleware?
Traditional ASP.NET exception filter can be used in abnormal manner, in the CORE ASP.NET, the pipes are connected in the form of a plurality of intermediate processing request, but the five common filter is retained, may also be employed exception filter to handle exceptions, but the exception filter can not handle the exception than the MVC middleware, in order to unify the overall consideration, the use of middleware to handle exceptions more appropriate
Why choose custom exception middleware?
Let's look at three ASP.NET CORE built-in exception handling middleware DeveloperExceptionPageMiddleware, ExceptionHandlerMiddleware, StatusCodePagesMiddleware
1.DeveloperExceptionPageMiddleware
can be given in detail of the request / back / error message, because it contains sensitive information, it is only suitable for the development environment
2.ExceptionHandlerMiddleware (Chiang God blog http://www.cnblogs.com/artech/p/error-handling-in-asp-net-core-3.html )
Only 500 error handling
3.StatusCodePagesMiddleware (Chiang God blog http://www.cnblogs.com/artech/p/error-handling-in-asp-net-core-4.html )
Handles the error between 400-599, but need not contain content Response (ContentLength = 0 && ContentType = null, the experiment can not respond in mvc uncaught exception)
Because of their limitations ExceptionHandlerMiddleware and StatusCodePagesMiddleware, both of which need to use with. In contrast custom middleware is more flexible, which would work on various error states unified treatment, treatment can be decided according to the configuration.
CustomExceptionMiddleWare
At the outset exception middleware configuration class
1 /// <summary> 2 /// 异常中间件配置对象 3 /// </summary> 4 public class CustomExceptionMiddleWareOption 5 { 6 public CustomExceptionMiddleWareOption( 7 CustomExceptionHandleType handleType = CustomExceptionHandleType.JsonHandle, 8 IList<PathString> jsonHandleUrlKeys = null, 9 string errorHandingPath = "") 10 { 11 HandleType = handleType; 12 = JsonHandleUrlKeys jsonHandleUrlKeys; 13 is ErrorHandingPath = errorHandingPath; 14 } 15 16 /// <Summary> . 17 /// Exception handling 18 is /// </ Summary> . 19 public CustomExceptionHandleType The HandleType { GET ; SET ;} 20 is 21 is /// < Summary> 22 is /// the Url Json processing mode key 23 is /// <para> take effect only when = Both the HandleType </ para> 24 /// </ Summary> 25 publicThe IList <PathString> JsonHandleUrlKeys { GET ; SET ;} 26 is 27 /// <Summary> 28 /// error jump page 29 /// </ Summary> 30 public PathString ErrorHandingPath { GET ; SET ;} 31 is } 32 33 is / // <Summary> 34 is /// error handling 35 /// </ Summary> 36 public enum CustomExceptionHandleType 37 [ { 38 is JsonHandle = 0 , // Json form processing 39 PageHandle = . 1 , // skip processing page 40 Both = 2 // automatic processing in accordance with the keyword Url 41 }
Member of the unusual statement middleware
/// <Summary> /// conduit delegate requests /// </ Summary> Private RequestDelegate -next; /// <Summary> /// configuration object /// </ Summary> Private CustomExceptionMiddleWareOption _option; /// <Summary > /// status code dictionary in need of treatment /// </ Summary> Private the IDictionary < int , String > exceptionStatusCodeDic; public CustomExceptionMiddleWare (RequestDelegate Next, CustomExceptionMiddleWareOption Option) { -next = Next; _option = Option; exceptionStatusCodeDic = new new the Dictionary < int , String > { { 401 , " unauthorized request " }, { 404 , " can not find the page " }, { 403 , " access denied " }, { 500 , " An unexpected server error has occurred " } // rest of the state of self-expansion }; }
The main exception middleware logic
. 1 public the async the Task the Invoke (the HttpContext context) 2 { . 3 Exception Exception = null ; . 4 the try . 5 { . 6 the await -next (context); // call to perform a lower duct intermediate piece . 7 } . 8 the catch (Exception EX) . 9 { 10 context. Response.Clear (); . 11 context.Response.StatusCode = 500 ; // uncaught exception occurs, the manual state code 12 is exception = EX; 13 } 14 finally 15 { 16 if (exceptionStatusCodeDic.ContainsKey(context.Response.StatusCode) && 17 !context.Items.ContainsKey("ExceptionHandled")) //预处理标记 18 { 19 var errorMsg = string.Empty; 20 if (context.Response.StatusCode == 500 && exception != null) 21 { 22 errorMsg = $"{exceptionStatusCodeDic[context.Response.StatusCode]}\r\n{(exception.InnerException != null ? exception.InnerException.Message : exception.Message)}"; 23 } 24 else 25 { 26 errorMsg = exceptionStatusCodeDic[context.Response.StatusCode]; 27 } 28 exception = new Exception(errorMsg); 29 } 30 31 if (exception != null) 32 { 33 var= HandleType _option.HandleType; 34 is IF (HandleType == CustomExceptionHandleType.Both) // determines According exception handling Url keyword 35 { 36 var requestPath = context.Request.Path; 37 [ HandleType = _option.JsonHandleUrlKeys =! null && _option. JsonHandleUrlKeys.Count ( 38 is K => requestPath.StartsWithSegments (K, StringComparison.CurrentCultureIgnoreCase))> 0 ? 39 CustomExceptionHandleType.JsonHandle: 40 CustomExceptionHandleType.PageHandle; 41 } 42 43 if (handleType == CustomExceptionHandleType.JsonHandle) 44 await JsonHandle(context, exception); 45 else 46 await PageHandle(context, exception, _option.ErrorHandingPath); 47 } 48 } 49 } 50 51 /// <summary> 52 /// 统一格式响应类 53 /// </summary> 54 /// <param name="ex"></param> 55 /// <returns></returns> 56 private ApiResponse GetApiResponse(Exception ex) 57 { 58 return new ApiResponse() { IsSuccess = false, Message = ex.Message }; 59 } 60 61 /// <summary> 62 /// 处理方式:返回Json格式 63 /// </summary> 64 /// <param name="context"></param> 65 /// <param name="ex"></param> 66 /// <returns></returns> 67 private async Task JsonHandle(HttpContext context, Exception ex) 68 { 69 var apiResponse = GetApiResponse(ex); 70 var serialzeStr = JsonConvert.SerializeObject(apiResponse); 71 context.Response.ContentType = "application/json"; 72 await context.Response.WriteAsync(serialzeStr, Encoding.UTF8); 73 } 74 75 /// <summary> 76 /// 处理方式:跳转网页 77 /// </summary> 78 /// <param name="context"></param> 79 /// <param name="ex"></param> 80 /// <param name="path"></param> 81 /// <returns></returns> 82 private async Task PageHandle(HttpContext context, Exception ex, PathString path) 83 { 84 context.Items.Add("Exception", ex); 85 var originPath = context.Request.Path; 86 context.Request.Path = path; -next (context); the await89 { 88the try87set the requested page to jump to an error page// 90 } 91 is the catch {} 92 the finally 93 { 94 context.Request.Path = originPath; // restore the originally requested page 95 } 96 }
Extended use of middleware classes registered
1 public static class CustomExceptionMiddleWareExtensions 2 { 3 4 public static IApplicationBuilder UseCustomException(this IApplicationBuilder app, CustomExceptionMiddleWareOption option) 5 { 6 return app.UseMiddleware<CustomExceptionMiddleWare>(option); 7 } 8 }
Sign exception middleware in Configuref method of Startup.cs
. 1 app.UseCustomException ( new new CustomExceptionMiddleWareOption ( 2 HandleType: CustomExceptionHandleType.Both, // The url keyword determination processing mode . 3 jsonHandleUrlKeys: new new PathString [] { " / API " }, . 4 errorHandingPath: " / Home / error " ));
Next we capture without exception to be tested, first to simulate a page will be jump
The results access / home / about the
Access / home / test results (the address does not exist)
OK way abnormal jump page of the test is completed, then we test the Exception Handling returns unified format (json), also a first analog anomalies are not captured
The results Access / api / token / gettesterror of
Access / api / token / test results (the address does not exist)
Access / api / token / getvalue results (the interface requires authentication)
The test is completed, the page jumps and unified format returned no problems, custom exception middleware has worked as expected
Note that the custom HTTP response to each middleware would request, processing logic must be streamlined to prevent unnecessary performance issues