准備翻譯dotnet tutorial網站上一些dotnet方面的知識文章。先從中間件開始,原文地址:
ASP.NET Core Middleware with Examples
本文主要討論以下與ASP.NET Core
中間件相關概念
- 什么是
ASP.NET Core
中間件 - 在
ASP.NET Core
應用的什么地方使用中間件 - 如何在
ASP.NET Core
應用中配置中間件 - 使用中間件的例子
ASP.NET Core
中間件的執行順序ASP.NET Core
中的請求代理是什么ASP.NET Core
中的Use,Run,Map方法的作用- 什么是
UseDeveloperExceptionPage
中間件 - 如何使用
Run()
和Use()
擴展方法配置中間件 - MapGet和Map方法的區別
什么是ASP.NET Core
中間件
ASP.NET Core
中間件是一種軟件組件(技術上僅僅是一些C#的類),聚合到應用管線用來處理Http請求和響應。每個中間件執行以下任務:
- 選擇是將Http請求傳遞到管線中的下一個中間件。通過調用中間件的next()方法實現。
- 能夠執行一些工作在管線的下一個中間件之前和之后。
ASP.NET Core
中有許多內置中間件已經可以直接使用。你也可以在你的ASP.NET Core
應用中根據需要創建自己的中間件。最重要的是,一個給定的ASP.NET Core
中間件只專注一個目的:即完成一個職責。
ASP.NET Core
應用中哪里使用中間件
ASP.NET Core
應用中使用中間件的一些例子:
- 使用一個中間件來做用戶認證
- 使用日志記錄請求和響應
- 使用一個中間件來處理錯誤(異常)
- 用來處理靜態文件,如圖片、javascript腳本或css樣式文件等
- 使用中間件來給用戶授權,指定特定訪問資源
中間件通常是我們用來處理 ASP.NET Core
應用請求管線。如果在先前版本的.NET Framework
工作過,你應該知道使用HTTP Handlers 和 HTTP Modules來創建請求處理管線。請求管線將決定HTTP請求和響應將如何執行。
如何在ASP.NET Core
應用中配置中間件
在ASP.NET Core
應用中,我們需要在Startup.cs文件中的Startup類中使用Configure()方法來配置中間件(.net5
以上版本沒有該類了)。Startup這個類是在應用開始時執行的。當我們使用空的ASP.NET Core
應用模板創建項目,將會生成如下帶有Configuration()方法的代碼:
當你需要配置中間件時,只需要在startup類中使用Configuration()方法中使用 IApplicationBuilder對象的Use方法。如上圖所示,Configuration()方法僅使用了3個中間件來創建請求處理管線。這3個中間件分別是:
UseDeveloperExceptionPage()
中間件UseRouting()
中間件UseEndpoints()
中間件
在理解以上三個內置中間件之前,先了解什么是中間件以及這些中間件如何在ASP.NET Core
應用中工作的。
理解中間件
在ASP.NET Core
應用中,中間件可以訪問到流入的HTTP請求和流出的HTTP響應,所以可以用來:
- 通過生成一個HTTP響應來處理流入的HTTP請求
- 處理並可以修改流入的HTTP請求,然后將該HTTP請求傳給管線上的下一個中間件
- 處理並可以修改流出的HTTP響應,並將HTTP響應傳遞給管線上的下一個中間件或
ASP.NET Core
應用(如果管線上已經沒有下一個中間件的話)
為了更好理解,下面的圖展示了ASP.NET Core
應用中處理管線如何執行。
如上圖所示,有一個日志中間件。這個中間件簡單的記錄下請求時間,然后將請求傳遞給下一個中間件-靜態文件處理中間件,用來做后續處理。
ASP.NET Core
應用中的中間件也可能通過創建HTTP響應來處理HTTP請求,也可能不調用請求管線中的下一個中間件。這個概念稱為:請求管線短路。
例如,有一個靜態文件中間件,如果流入HTTP請求是某些靜態文件,如圖片、CSS樣式文件、JavaScript腳本文件等,靜態文件中間件就可以處理該請求了,它將不再調用請求管線中下一個中間件:MVC中間件,以此來短路請求管線。
ASP.NET Core
應用中的中間件不僅能夠訪問HTTP請求,也可以訪問管線中的響應。例如,在本例中的日志中間件可能記錄下響應發送給客戶端的時間。
ASP.NET Core
中的中間件執行順序
理解中間件執行順序非常重要。ASP.NET Core
應用中間件執行順序是按照他們加入管線的順序。所以,當往請求處理管線中加入中間件時需要非常注意順序。
按照你的應用需求,你可能會添加任意數量的中間件。例如,如果你開發的僅僅是靜態網站來處理一些靜態的HTML頁面和圖片,那么你僅需要在請求管線中添加“靜態文件”中間件。
如果你開發的是安全的動態數據驅動web應用,那么你將需要多個中間件來完成任務,例如日志中間件,認證中間件,授權中間件,MVC中間件等。
ASP.NET Core
中的請求代理是什么
在ASP.NET Core
中,請求代理用來創建請求管線,即請求代理是用來處理每個流入HTTP請求的。在 ASP.NET Core
中,你可以使用Run,Map,Use擴展方法來配置請求代理。你可以使用一個匿名方法(中間件in-line方式)或者創建一個可復用的類來實現請求代理。這些匿名方法或可復用的類即成為中間件或中間件組件。請求管線中的每個中間件都可以觸發或短路下一個中間件。
ASP.NET Core
中的Run()
和Use()
擴展方法配置中間件
在 ASP.NET Core
中,使用Use和Run擴展方法來向請求管線中注冊行內中間件。Run擴展方法允許我們添加終點中間件(即該中間件后面不會再有中間件了)。另一方面,Use擴展方法允許我們項請求管線中添加可以繼續調用下一個中間件的中間件。
如果你觀察Configure方法,你會看到它獲取了一個IApplicationBuilder接口的實例,然后使用該實例的擴展方法如Use、Run來配置中間件組件。
在上面的示例,3個中間件通過使用IApplicationBuilder的示例注冊到請求管線中。他們分別是:
- UseDeveloperExceptionPage()中間件
- UseRouting()
- UseEndpoints() 中間件
UseDeveloperExceptionPage
中間件
在Configure方法中,UseDeveloperExceptionPage()
中間件注冊到請求管線中,該中間件僅在服務器環境被設置為“development”時才會顯示一個圖片。該中間件僅當應用中出現一個未處理的異常發生且時在開發模式下,會顯示出現問題的代碼。你可以考慮使用黃色頁面來代替。稍后下一篇文章將會示例如何使用中間件。
UseRouting()
中間件
該中間件組件用於添加端點路由中間件到請求管線,該中間件將URL(或者流入HTTP請求)映射到一個特定的資源。將會在后面路由相關的文章討論細節。
UseEndpoints()
中間件
在這個中間件,使用Map擴展方法路由決定。下面是UseEndpoints中間件的默認實現。MapGet擴展方法,我們將路由設置為"/",說明僅匹配域名。即任何僅包含域名的請求URL均由該中間件處理
除了使用MapGet方法,你話可以使用Map方法來映射。
此時運行應用,你將獲得預期的輸出。
MapGet和Map方法的區別
MapGet方法僅處理GET方法的HTTP請求,而Map方法則可以處理GET、POST、PUT以及DELETE的HTTP請求。
如何使用Run擴展方法配置中間件
接下來我們使用Run擴展方法創建並配置自定義的中間件。首先,Configure方法中有所有的代碼注釋。你可以注釋掉所有已有代碼,然后復制黏貼下面的代碼到Configure方法中。下面的代碼向請求管線中注冊了一個簡單的中間件,該中間件僅打印一些消息。
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.Run(async (context) =>
{
await context.Response.WriteAsync("Getting Response from First Middleware");
});
}
輸出:
我們觸發IApplicationBuilder實例(app變量)Run擴展方法,注冊該中間件至請求管線。下面是Run方法的定義。
從上面Run方法定義可以看出,該方法實現IApplicationBuilder接口的擴展方法。這是為什么可以使用IApplicationBuilder的實例app調用Run擴展方法。如果你對擴展方法不熟悉,可以先閱讀下面文章。
https://dotnettutorials.net/lesson/extension-methods-csharp/
從上面圖片也能看出,Run方法接收一個輸入參數,類型為RequestDelegate。下面是RequestDelegate的定義。
從上面圖片看出,RequestDelegate代理一類方法,該類方法接收一個類型為HttpContext的參數。如果你對代理不熟悉,可以閱讀下面文章。
https://dotnettutorials.net/lesson/delegates-csharp/
前面一直討論到的ASP.NET Core
中間件既能夠訪問HTTP Request,也能訪問HTTP Response,就是因為上面的那個HttpContext對象。
在我們的例子中,我們以行內匿名方法傳遞一個請求代理,並且傳遞HTTPContext對象作為輸入參數給請求代理。如下圖所示:
注意:除了使用行內匿名方法傳遞請求代理外,你也可以定義一個獨立類來傳遞請求代理。后面文章將討論。
再添加一個中間件
修改Configure方法內的代碼如下,用來再添加一個中間件:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.Run(async (context) =>
{
await context.Response.WriteAsync("Getting Response from First Middleware");
});
app.Run(async (context) =>
{
await context.Response.WriteAsync("Getting Response from Second Middleware");
});
}
現在用Run擴展方法注冊了2個中間件。如果你運行應用,將獲得如下輸出
Getting Response from 1st Middleware
僅打印出第一個中間件的輸出。原因是我們使用Run擴展方法來注冊的中間件,使用該方法注冊的中間件為端點中間件,即他們不會再調用請求管線后面的中間件了。
使用Use擴展方法配置中間件
那么問題來了,如何調用請求管線后面的中間件呢?答案是使用Use擴展方法來注冊中間件。如下代碼所示。
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.Use(async (context, next) =>
{
await context.Response.WriteAsync("Getting Response from 1st Middleware");
await next();
});
app.Run(async (context) =>
{
await context.Response.WriteAsync("Getting Response from 2nd Middleware");
});
}
現在運行應用,將會得打預期的輸出,即兩個中間件的輸出均顯示出來了。
理解Use擴展方法
Use擴展方法以行內方式添加一個中間件代理到請求管線中。下面是Use擴展方法的定義:
該方法也是作為IApplicationBuilder接口的一個擴展方法來實現。這也是我們能夠使用IApplicationBuilder實例觸發該方法的原因。從該方法定義中可以看出,方法使用兩個輸入參數,第一個參數是HttpContext對象,通過它可以訪問HTTP請求和響應。第二個參數是Func類型,一個泛型代理,可以處理請求或調用請求管線中的下一個中間件。
注意:如果你想向下一個中間件傳遞請求,那么你需要調用next方法。
本篇至此結束,下一篇將舉例使用自定義中間件。本篇嘗試解釋中間件如何在ASP.NET Core
應用中處理請求管線。
譯者添加
這是第一篇嘗試翻譯的文章,盡量理解原作者意思。以后我都會在后面加上譯者,添加一些自己的想法。
由於本篇原作者寫的時候,使用的應該是ASP.NET Core 5
版本以下,所有示例代碼均在低版本下。5.0以上已經沒有StartUp.cs文件了,因此實現上略有區別。會在下一篇翻譯完作者舉例使用自定義中間件的時候,同時給出高版本的中間件實現方式。