深入淺出:ASP.NET Core 中間件的使用與封裝
在 ASP.NET Core 中,中間件(Middleware)是處理 HTTP 請求和響應的核心組件。中間件可以在請求到達最終處理前對請求進行處理,也可以在響應返回客戶端之前修改響應。通過使用中間件,開發者能夠靈活地擴展應用程序功能,處理認證、日志記錄、跨域請求、錯誤處理等常見任務。
本文將詳細介紹 ASP.NET Core 中間件的工作原理、如何使用內置中間件、如何封裝自定義中間件,并提供實際的例子來幫助你掌握中間件的使用技巧。
1. 什么是中間件?
中間件是一個處理請求和響應的組件,它構成了 ASP.NET Core 應用程序的請求處理管道。在請求到達應用時,ASP.NET Core 會通過每個中間件對請求進行處理,然后最終返回響應。在管道中的每個中間件都可以:
- 處理請求:例如,驗證請求的有效性、記錄日志、修改請求內容等。
- 調用下一個中間件:中間件可以選擇將請求傳遞給管道中的下一個中間件,或者直接終止請求處理(例如直接返回響應)。
- 修改響應:在請求處理結束后,中間件還可以對響應進行修改。
中間件的執行順序
ASP.NET Core 中間件的執行順序是非常重要的。你配置中間件的順序決定了請求和響應的處理流程。例如:
- 靜態文件中間件(如
UseStaticFiles)應該盡量放在管道的前面,以便盡早處理靜態文件請求。 - 身份驗證中間件(如
UseAuthentication)通常應該在授權中間件(UseAuthorization)之前執行,以確保用戶身份的驗證。 - 異常處理中間件(如
UseExceptionHandler)應該放在所有其他中間件的上面,以捕獲并處理任何異常。
2. 創建和使用自定義中間件
2.1 創建自定義中間件
自定義中間件是你編寫的、用于處理請求和響應的業務邏輯組件。你可以通過實現一個類,并在類中定義一個 InvokeAsync 或 Invoke 方法來創建中間件。
示例:記錄請求處理時間的中間件
public class RequestTimingMiddleware
{
private readonly RequestDelegate _next;
public RequestTimingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
var startTime = DateTime.Now; // 記錄請求開始時間
// 調用下一個中間件
await _next(context);
var endTime = DateTime.Now; // 請求結束時間
var elapsedTime = endTime - startTime;
// 記錄請求處理時間
Console.WriteLine($"Request processing time: {elapsedTime.TotalMilliseconds} ms");
// 在響應頭中添加請求處理時間
context.Response.Headers["X-Processing-Time-ms"] = elapsedTime.TotalMilliseconds.ToString();
}
}
2.2 注冊自定義中間件
將中間件類注冊到請求管道中,在 Program.cs 或 Startup.cs 文件的 Configure 方法中進行配置。這樣,當請求進入應用時,它會依次經過管道中的中間件。
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// 注冊自定義中間件
app.UseMiddleware<RequestTimingMiddleware>();
// 配置請求管道
app.MapGet("/", () => "Hello, World!");
app.Run();
}
}
在上述代碼中,RequestTimingMiddleware 中間件會計算每個請求的處理時間,并將該時間添加到響應的頭部中。
3. 如何封裝和復用中間件
封裝中間件是指將中間件的邏輯從應用代碼中分離出來,使其能夠在不同的應用或多個地方復用。封裝好的中間件可以處理常見的任務,比如錯誤處理、日志記錄等。
3.1 捕獲異常的中間件
一個常見的封裝中間件的場景是全局異常捕獲。這種中間件會捕獲應用中未處理的異常,記錄異常信息,并返回統一的錯誤響應。
public class ExceptionHandlingMiddleware
{
private readonly RequestDelegate _next;
public ExceptionHandlingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
try
{
// 調用管道中的下一個中間件
await _next(context);
}
catch (Exception ex)
{
// 記錄異常
Console.WriteLine($"Exception caught: {ex.Message}");
// 返回統一的錯誤響應
context.Response.StatusCode = 500; // 內部服務器錯誤
await context.Response.WriteAsync("An unexpected error occurred.");
}
}
}
3.2 使用依賴注入(DI)封裝中間件
中間件也可以使用依賴注入(DI)來注入應用程序中的服務。例如,你可能需要在中間件中使用日志記錄服務來記錄請求的詳細信息。
public class LoggingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<LoggingMiddleware> _logger;
public LoggingMiddleware(RequestDelegate next, ILogger<LoggingMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
_logger.LogInformation("Request started at: " + DateTime.Now);
// 調用下一個中間件
await _next(context);
_logger.LogInformation("Request completed at: " + DateTime.Now);
}
}
注冊 DI 服務并將中間件添加到管道中:
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// 配置服務
builder.Services.AddLogging();
var app = builder.Build();
// 使用 LoggingMiddleware
app.UseMiddleware<LoggingMiddleware>();
// 配置請求管道
app.MapGet("/", () => "Hello, World!");
app.Run();
}
}
在這個例子中,LoggingMiddleware 中間件通過依賴注入獲取了日志記錄器,并在處理請求時記錄了請求的開始和結束時間。
4. 常見的內置中間件
ASP.NET Core 提供了許多常見的內置中間件,可以幫助開發者快速實現常見的功能。以下是一些常用的內置中間件及其配置方法:
4.1 靜態文件中間件(UseStaticFiles)
靜態文件中間件用于提供靜態文件(如 HTML、CSS、JavaScript、圖片等)給客戶端。
app.UseStaticFiles(); // 默認會提供 wwwroot 目錄中的靜態文件
4.2 身份驗證中間件(UseAuthentication 和 UseAuthorization)
身份驗證和授權中間件用于處理用戶身份驗證和訪問控制。
app.UseAuthentication(); // 啟用身份驗證
app.UseAuthorization(); // 啟用授權
4.3 錯誤處理中間件(UseExceptionHandler)
錯誤處理中間件捕獲應用中的異常并執行自定義的錯誤處理邏輯。
app.UseExceptionHandler("/Home/Error"); // 捕獲全局異常并重定向到指定的錯誤頁面
4.4 跨源資源共享(CORS)中間件(UseCors)
跨源資源共享(CORS)中間件用于允許不同源的客戶端訪問你的 API。
app.UseCors(policy => policy.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
5. 中間件的順序
中間件的執行順序決定了請求處理的方式。你必須在配置管道時確保中間件的順序正確。例如,靜態文件中間件通常應該排在最前面,以便它可以直接返回靜態文件,避免進一步的請求處理。身份驗證和授權通常應該在路由中間件之前執行。
app.UseExceptionHandler("/Home/Error"); // 錯誤處理應該排在最前
app.UseStaticFiles(); // 靜態文件處理
app.UseRouting(); // 路由
app.UseAuthentication(); // 身份驗證
app.UseAuthorization(); // 授權
app.MapControllers(); // 映射控制器
總結
ASP.NET Core 的中間件為我們提供了靈活且強大的機制來擴展和處理 HTTP 請求和響應。通過自定義中間件,封裝常見功能以及合理配置中間件順序,我們能夠構建更加可維護、模塊化
和高效的應用程序。無論是記錄請求日志、處理異常,還是提供跨域支持,中間件都能幫助我們輕松實現。希望本文的示例和講解能夠幫助你更好地理解和使用 ASP.NET Core 中間件。

浙公網安備 33010602011771號