目前版本是Asp.Net Core v1.1,這個版本的感受對Http請求中的錯誤處理方便不是很完善。html
沒有HttpException異常類,不能在任何的地方自由的拋出對應的異常狀態。json
1、默認的異常處理配置app
1.默認配置在StartUp文件的Configure中註冊錯誤處理async
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); } }
特別說明:ide
1.env.IsDevelopment() 用於判斷當前運行環境是不是測試環境post
2.app.UseDeveloperExceptionPage(); 若是是測試環境則啓用開發者異常頁面測試
開發者異常頁面ui
當在Web處理管道放生了一個位置異常時,開發者異常頁面會顯示有用的調試信息。頁面包含幾個選項卡顯示Stack、Query、Cookie、Header異常信息。this
3.app.UseExceptionHandler("/Home/Error"); 在正式運行環境中輸出異常的內容信息。編碼
4.默認的異常處理對於404沒有處理,若是是404的地址則返回空內容。
5.業務邏輯404的拋出
使用狀態視圖
public IActionResult Test2() { //手動拋出404 頁面 return StatusCode(404, "你要訪問的頁面不存在"); }
或者修改相應上下文的狀態碼
@{ //自定義拋出404異常 this.Context.Response.StatusCode = 404; } <h1>404狀態的頁面</h1>
2、錯誤處理擴展,使用委託
1.
//此處的404頁面,只能用於處理路由中不匹配的404頁面 //若是是程序邏輯中的404不予以處理 //而且對於程序中Exception 也不作處理,直接相應500,內容爲空 RequestDelegate handler = async context => { var resp = context.Response; if (resp.StatusCode == 404) { await resp.WriteAsync($"當前是404頁面,暫時沒有獲取到異常內容"); } }; app.UseStatusCodePages(builder => { builder.Run(handler); });
2.
//使用StatusCodePagesMiddleware 指定狀態對應的顯示頁面 Func<StatusCodeContext, Task> handler = async context => { var resp = context.HttpContext.Response; if (resp.StatusCode == 404) { //須要 using Microsoft.AspNetCore.Http; await resp.WriteAsync($"當前是404頁面,暫時沒有獲取到異常內容", Encoding.UTF8); } else if (resp.StatusCode == 500) { await resp.WriteAsync($"當前是500頁面,暫時沒有獲取到異常內容", Encoding.UTF8); } }; app.UseStatusCodePages(handler);
3、錯誤處理擴展,使用自定義擴展類
Asp.Net Core三種呈現錯誤也的方式均可以擴展
1.DeveloperExceptionPageMiddleware中間件的擴展能夠自定義開發者異常頁面,當前略過
2.ExceptionHandlerMiddleware中間件,能夠自定義擴展異常處理
示例,處理異常並制定異常的響應頁面
public class ErrorHandlingMiddleware { private RequestDelegate _next; private ExceptionHandlerOptions _options; public ErrorHandlingMiddleware(RequestDelegate next, IOptions<ExceptionHandlerOptions> options) { _next = next; _options = options.Value; } public async Task Invoke(HttpContext context) { try { await _next(context); } catch { //雖然此處指定500,可是出現異常,再次執行異常頁面則響應的是200 context.Response.StatusCode = 500; context.Response.Clear(); if (_options.ExceptionHandlingPath.HasValue) { context.Request.Path = _options.ExceptionHandlingPath; } RequestDelegate handler = _options.ExceptionHandler ?? _next; await handler(context); } } }
使用擴展方法爲IApplicationBuilder擴展內容
public static class ErrorHandlingExtensions { public static IApplicationBuilder UseErrorHandling(this IApplicationBuilder builder, ExceptionHandlerOptions options) { return builder.UseMiddleware<ErrorHandlingMiddleware>(Options.Create(options)); } }
在 Configure中註冊當前錯誤處理
//使用自定義異常處理 app.UseErrorHandling(new ExceptionHandlerOptions() { //注意此處的路徑不能使用~符號 ExceptionHandlingPath = "/Home/Error" });
3.StatusCodePagesMiddleware中間件能夠根據正常的相應內容(沒有拋出異常的狀況下) 擴展狀態相應頁面
public interface IStatusCodePagesFeature { bool Enabled { get; set; } } public class StatusCodePagesFeature : IStatusCodePagesFeature { public bool Enabled { get; set; } = true; } public class StatusCodePagesMiddleware { private RequestDelegate _next; private StatusCodePagesOptions _options; public StatusCodePagesMiddleware(RequestDelegate next, IOptions<StatusCodePagesOptions> options) { _next = next; _options = options.Value; } public async Task Invoke(HttpContext context) { //能夠用於阻止異常處理 StatusCodePagesFeature feature = new StatusCodePagesFeature(); context.Features.Set<IStatusCodePagesFeature>(feature); await _next(context); HttpResponse response = context.Response; //對於響應的狀態編碼,返回內容 //if ((response.StatusCode >= 400 && response.StatusCode <= 599) && !response.ContentLength.HasValue && string.IsNullOrEmpty(response.ContentType)) if (response.StatusCode >= 400 && response.StatusCode <= 599 && feature.Enabled) { //觸發 默認處理 //await _options.HandleAsync(new StatusCodeContext(context, _options, _next)); //對於非異常的頁面,執行Clear拋出異常 //response.Clear(); //response.Body.Seek(0, SeekOrigin.Begin); await response.WriteAsync($"當前HttpCode={response.StatusCode}"); } } }
使用擴展方法註冊中間件
public static class ErrorHandlingExtensions {//註冊3中處理方式 public static IApplicationBuilder UseStatusCodeHandling(this IApplicationBuilder builder) { return builder.UseMiddleware<StatusCodePagesMiddleware>(); } public static IApplicationBuilder UseStatusCodeHandling(this IApplicationBuilder app, StatusCodePagesOptions options) { return app.UseMiddleware<StatusCodePagesMiddleware>(Options.Create(options)); } public static IApplicationBuilder UseStatusCodeHandling(this IApplicationBuilder app, Func<StatusCodeContext, Task> handler) { return app.UseStatusCodePages(new StatusCodePagesOptions { HandleAsync = handler }); } }
在Configure中註冊使用
Func<StatusCodeContext, Task> handler = async context => { var resp = context.HttpContext.Response; //在如下的相應數據時,會清空原頁面的相應內容 if (resp.StatusCode == 404) { //須要 using Microsoft.AspNetCore.Http; await resp.WriteAsync($"當前是404頁面,暫時沒有獲取到異常內容", Encoding.UTF8); } else if (resp.StatusCode == 500) { await resp.WriteAsync($"當前是500頁面,暫時沒有獲取到異常內容", Encoding.UTF8); } }; app.UseStatusCodeHandling(handler);
4.能夠在擴展中綜合使用處理,以下示例
public class ErrorHandlingMiddleware { private readonly RequestDelegate next; private ExceptionHandlerOptions _options; public ErrorHandlingMiddleware(RequestDelegate next, IOptions<ExceptionHandlerOptions> options) { this.next = next; this._options = options.Value; } public async Task Invoke(HttpContext context) { try { await next(context); } catch (Exception ex) { var statusCode = context.Response.StatusCode; if (ex is ArgumentException) { statusCode = 200; } await HandleExceptionAsync(context, statusCode, ex.Message); } finally { var statusCode = context.Response.StatusCode; var msg = ""; if (statusCode == 401) { msg = "未受權"; } else if (statusCode == 404) { //msg = "未找到服務"; //若是是404 返回404頁面 if (_options.ExceptionHandlingPath.HasValue) { context.Request.Path = _options.ExceptionHandlingPath; } RequestDelegate handler = _options.ExceptionHandler ?? next; await handler(context); } else if (statusCode == 502) { msg = "請求錯誤"; } else if (statusCode != 200) { msg = "未知錯誤"; } if (!string.IsNullOrWhiteSpace(msg)) { await HandleExceptionAsync(context, statusCode, msg); } } } private static Task HandleExceptionAsync(HttpContext context, int statusCode, string msg) { var data = new { code = statusCode.ToString(), is_success = false, msg = msg }; var result = JsonConvert.SerializeObject(new { data = data }); try { //特別說明ContentType屬性在 HttpResponse初始化完成以後就不能修改了 //若是試圖修改則拋出異常 //異常內容:Headers are read-only, response has already started. //context.Response.ContentType = "application/json;charset=utf-8"; //特別說明對於準備輸出的Response,執行Clear()清空拋出異常 //The response cannot be cleared, it has already started sending. context.Response.Clear(); //判斷輸出流是否已經開始 //context.Response.HasStarted } catch (Exception ex) { //throw ex; } //清楚已經完成的相應內容 return context.Response.WriteAsync(result); } }
原文參考:http://www.cnblogs.com/artech/p/error-handling-in-asp-net-core-1.html
更多: