本文將介紹在ASP.Net Core中處理異常的幾種方法
- 1使用開發(fā)人員異常頁面(The developer exception page)
- 2配置HTTP錯誤代碼頁 Configuring status code pages
- 3使用MVC過濾器 ExceptionFilter
- 4 自定義異常捕獲中間件 Middleware
一使用開發(fā)人員異常頁面(The developer exception page)
配置你的程序使其在發(fā)生異常時詳細的展示異常信息
- 安裝
Microsoft.AspNetCore.Diagnostics
NuGet package
.net core 2.0中包含Microsoft.AspNetCore.All,這里面包含了Microsoft.AspNetCore.Diagnostics暑脆,無需自安裝土匀。 - 在Startup.cs 上添加對exception page的使用Configure method in the Startup class:
public void Configure(IApplicationBuilder app)
{
app.UseDeveloperExceptionPage();//使用異常記錄頁面
}
在控制器中拋一個異常:
public class HomeController : Controller
{
public IActionResult Index()
{
throw new Exception();
return View();
}
}
在開發(fā)環(huán)境下運行,異常展示頁面包含幾個標簽展示異常信息和HTTP請求。第一個選項卡包含一個堆棧跟蹤
它下一個選項卡顯示查詢字符串參數(shù),如果有的話。
第三個是Cookies和Headers信息
提示:在任何你想要捕捉異常的中間件(middleware)之前注冊UseDeveloperExceptionPage 比如 app.UseMvc.
一般在項目開發(fā)中筐带,UseDeveloperExceptionPage展示異常詳情信息對開發(fā)過程很有幫助,但在項目發(fā)布出去以后扣孟,在系統(tǒng)發(fā)生異常時更明智的是向用戶展示一個靜態(tài)的錯誤頁面烫堤。這時就要做如下更改了:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
//判斷是否是開發(fā)環(huán)境
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/error");
}
依據(jù)上面代碼,app.UseExceptionHandler("/error");
在生產環(huán)境下凤价,發(fā)生系統(tǒng)錯誤時,跳轉到錯誤頁面
二配置HTTP錯誤代碼頁 Configuring status code pages
如果訪問項目上一個不存在的頁面拔创,會如下顯示:
修改 Startup.Configure利诺,使其能夠使用HTTP錯誤代碼頁
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
//開發(fā)環(huán)境異常處理
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
}
else
{
//生產環(huán)境異常處理
app.UseExceptionHandler("/Home/Error");
}
app.UseStatusCodePages();//使用HTTP錯誤代碼頁
}
再次訪問不存在的頁面
app.UseStatusCodePages
支持多種擴展方法。其中一個方法接受一個lambda表達式:
app.UseStatusCodePages(async context =>
{
context.HttpContext.Response.ContentType = "text/plain";
await context.HttpContext.Response.WriteAsync(
"Status code page, status code: " +
context.HttpContext.Response.StatusCode);
});
還可以跳轉到指定頁面剩燥,并附加Response.StatusCode
app.UseStatusCodePagesWithReExecute("/Home/Error/{0}");
占位符{0}在這代表Response.StatusCode 如:404
三使用MVC過濾器
// <summary>
/// 自定義全局異常過濾器
/// </summary>
public class GlobalExceptionFilter : IExceptionFilter
{
readonly ILoggerFactory _loggerFactory;//采用內置日志記錄
readonly IHostingEnvironment _env;//環(huán)境變量
public GlobalExceptionFilter(ILoggerFactory loggerFactory, IHostingEnvironment env)
{
_loggerFactory = loggerFactory;
_env = env;
}
public void OnException(ExceptionContext context)
{
var controller = context.ActionDescriptor;
ILog log = LogManager.GetLogger(Startup.Repository.Name, controller.ToString());//初始化Log4net日志
#region 記錄到內置日志
//var logger = _loggerFactory.CreateLogger(context.Exception.TargetSite.ReflectedType);
//logger.LogError(new EventId(context.Exception.HResult),
//context.Exception,
//context.Exception.Message);
#endregion
if (_env.IsDevelopment())
{
log.Error(context.Exception.ToString());
//var JsonMessage = new ErrorResponse("未知錯誤,請重試");
//JsonMessage.DeveloperMessage = context.Exception;
//context.Result = new ApplicationErrorResult(JsonMessage);
//context.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
//context.ExceptionHandled = true;
}
else
{
log.Error(context.Exception.ToString());
context.ExceptionHandled = true;
context.Result=new RedirectResult("/home/Error");
}
}
public class ApplicationErrorResult : ObjectResult
{
public ApplicationErrorResult(object value) : base(value)
{
StatusCode = (int)HttpStatusCode.InternalServerError;
}
}
public class ErrorResponse
{
public ErrorResponse(string msg)
{
Message = msg;
}
public string Message { get; set; }
public object DeveloperMessage { get; set; }
}
}
}
使用OnException方法慢逾,當異常發(fā)生時,調用這個方法灭红。
在上面代碼中侣滩,根據(jù)項目環(huán)境的不同,分開處理異常变擒。
-
當開發(fā)環(huán)境中君珠,通過Log4net把日志記錄到本地文件中。再這里注釋了一句很重要代碼
context.ExceptionHandled = true;//代表異常已經處理
娇斑,context.ExceptionHandled 代表異常是否處理策添,不是true時材部,異常記錄到日志文件中后,系統(tǒng)對異常的處理并未結束唯竹,如果這時系統(tǒng)使用了開發(fā)人員異常頁面(The developer exception page)
,系統(tǒng)在頁面上詳細展示系統(tǒng)異常信息乐导。若果context.ExceptionHandled
為true,異常通過Log4net把日志記錄到本地文件后浸颓,系統(tǒng)對異常的處理就結束了物臂。
-
生產環(huán)境下,通過Log4net把日志記錄到本地文件中后产上,context.ExceptionHandled = true;系統(tǒng)處理異常結束棵磷,讓系統(tǒng)跳轉到靜態(tài)錯誤頁。
四自定義異常捕獲中間件 Middleware
對于一些非MVC引起的異常蒂秘,MVC過濾器是不能捕獲異常的泽本。
什么是中間件?
中間件是一種組裝到系統(tǒng)應用程序的請求管道用來處理請求和相應的框架。它的各個構成:
1) 在程序管道中是否選擇將請求傳遞給下一個組件姻僧。
2)可以在系統(tǒng)請求管道的下一個中間件的執(zhí)行的前面或者后面處理請求和相應
一個委托請求被用來構建請求管道规丽。這個委托請求用來處理每一個HTTP請求。
委托請求使用方法Run,Map 和使用Use方法的擴展方法來配置
自己可以指定創(chuàng)建一個匿名的委托請求in-iline撇贺,也可以將將其定義在一個可重用的類里面赌莺。
這些可重用的類和in-line匿名方法就稱為中間件,或者中間組件。
在請求管道中的每一個中間件的任務就是調用下一個中間件松嘶,特定場景下也可以越過下一個中間件直接返回結果艘狭。
下面是一個自定義ExceptionHandlingMiddleware中間件的過程,當捕獲到異常時翠订,存到日志中巢音。
/// <summary>
/// 自定義異常處理中間件
/// </summary>
public class ExceptionHandlingMiddleware
{
private readonly RequestDelegate _next;
public ExceptionHandlingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
var statusCode = context.Response.StatusCode;
await HandleExceptionAsync(context, ex.ToString());
}
}
private Task HandleExceptionAsync(HttpContext context, string msg)
{
HandleExceptionHelper hannd = new HandleExceptionHelper();
hannd.log.Error(msg);//記錄到日志文件
return context.Response.WriteAsync("ERROR");
}
}
在定義一個異常的中間件,并拋一個異常尽超,用ExceptionHandlingMiddleware捕獲異常
app.Use(async (context, next) =>
{
throw new Exception();
await next.Invoke();
});