異常處理,也可以做得很優雅。
一、前言
異常處理的重要性,老司機都清楚。
這篇文章,我們來理一下Dotnet Core異常處理的幾種方式。
- Try Catch方式
- Exception Filter方式
- 內建的異常處理中間件
- 自定義的異常處理中間件
這是目前使用比較多的幾種方式。其中,第1、2種其實算是一種,是C#兩個語言版本的東西。
為了防止不提供原網址的轉載,特在這里加上原文鏈接:https://www.cnblogs.com/tiger-wang/p/13562817.html
二、Try Catch方式
這是最通常使用的一種方式。
看例子:
[HttpGet]
public IActionResult Get()
{
try
{
List<string> example_list = null;
var item_count = example_list.Count();
return Ok(item_count);
}
catch (Exception ex)
{
return StatusCode(HttpContext.Response.StatusCode, ex.Message);
}
}
有時候,我們可能需要處理多種異常。
catch (Exception ex)
{
if(ex.InnerException == null)
return StatusCode(HttpContext.Response.StatusCode, "error");
else
return StatusCode(HttpContext.Response.StatusCode, "other error");
}
在C# 6以后,Try Catch加了一個過濾Exception Filter
語法,可以在catch
后跟一個條件語句。上面這個catch
可以寫為:
catch (Exception ex) when (ex.InnerException == null)
{
return StatusCode(HttpContext.Response.StatusCode, "error");
}
catch (Exception ex)
{
return StatusCode(HttpContext.Response.StatusCode, "other error");
}
在這個語法中,when
后面是一個bool
的判斷,為true
則進入catch
塊,為false
則跳過。
在C#中,異常是從內向外逐層查找處理程序的,隨着查找層數的增加,性能會逐漸降低。
概念上,try
塊的運行效率和不加try
塊的性能差不多,可以認為基本一致;但catch
塊的性能會差很多。所以一般來說,一個基本的原則是,不要把try
、catch
作為程序的邏輯。
但是,如果我們需要又需要記錄這個異常,該怎么辦?
這時候,就可以利用Exception Filter
語法。
看代碼:
[HttpGet]
public IActionResult Get()
{
try
{
List<string> example_list = null;
var item_count = example_list.Count();
return Ok(item_count);
}
catch (Exception ex) when (log(ex))
{
}
return StatusCode(HttpContext.Response.StatusCode, "error");
}
private bool log(Exception ex)
{
Debug.Print(ex.Message);
return false;
}
在這個代碼中,when
條件后跟了一個返回bool
的方法。我們可以在這個方法中進行異常的記錄處理,然后返回false
。
為什么要返回false
呢?是因為我們要記錄異常,但為了性能的考慮,不希望代碼進入到catch
塊。返回false
后,程序執行了log
方法,卻又沒進入到catch
塊。
當然,如果你想進入到catch
塊,那返回true
就可以了。
嗯。這一段能看明白就行了,這不算是一個常規的解決辦法,只能算一個旁門的小技巧。
三、內建的異常中間件
內建的異常處理,有兩個。
一個是我們最常見的,在創建webapi
類型的工程時,Startup.cs
文件中已經默認生成好的:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
}
這個app.UseDeveloperExceptionPage
就是框架中用於顯示異常的詳細信息的中間件。
另一個,是app.UseExceptionHandler
,也是一個內置的用來處理異常的中間件,可以這樣用:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseExceptionHandler(para...);
}
參數可以是一個Endpoint
,也可以是一個Action
。實際應用時,還可以寫成一個IApplicationBuilder
的擴展。
四、自定義的中間件
如果對異常管理有很高的要求,自定義異常處理中間件,是最合適的一種方式。
中間件的寫法,我在前文一文說通Dotnet Core的中間件中有詳細的說明,這兒不再多說。
給一段例子看看:
public class CustomExceptionMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<CustomExceptionMiddleware> _logger;
public CustomExceptionMiddleware(RequestDelegate next, ILogger<CustomExceptionMiddleware> logger)
{
_logger = logger;
_next = next;
}
public async Task InvokeAsync(HttpContext httpContext)
{
try
{
await _next(httpContext);
}
catch (Exception ex)
{
_logger.LogError($"Exception occur: {ex}");
await HandleExceptionAsync(httpContext, ex);
}
}
private Task HandleExceptionAsync(HttpContext context, Exception exception)
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
return context.Response.WriteAsync(new CustomError()
{
StatusCode = context.Response.StatusCode,
Message = "custom middleware error."
}.ToString());
}
}
使用時,就在Configure
里引入即可。
(全文完)
本文的代碼已上傳到Github,位置在:https://github.com/humornif/Demo-Code/tree/master/0023/demo/demo
![]() |
微信公眾號:老王Plus 掃描二維碼,關注個人公眾號,可以第一時間得到最新的個人文章和內容推送 本文版權歸作者所有,轉載請保留此聲明和原文鏈接 |