配置 ASP.NET Core 請求(Request)處理管道 在本節中,我們將討論使用中間件組件為 asp.net core 應用程式配置請求處理管道。 作為應用程式啟動的一部分,我們要在Configure()方法中設置請求處理管道。 目前我們的代碼中有 2 個中間件在管道中 :UseDevelo ...
配置 ASP.NET Core 請求(Request)處理管道
在本節中,我們將討論使用中間件組件為 asp.net core 應用程式配置請求處理管道。
作為應用程式啟動的一部分,我們要在Configure()
方法中設置請求處理管道。
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World!");
});
}
}
目前我們的代碼中有 2 個中間件在管道中 :UseDeveloperExceptionPage()方法和Run()方法
UseDeveloperExceptionPage 中間件:顧名思義,如果存在異常並且環境是Development
,此中間件會被調用,顯示開發異常頁面。 我們將在後面的視頻中討論這個DeveloperExceptionPage 中間件和環境變數的使用。
第二個中間件是註冊Run()
方法到管道中,它只能處理將一個信息傳入Response
對象。 目前,它是一個響應每個請求的中間件,返回 Hello world。 在這種情況下,無論您的請求路徑是什麼。 所有請求都會被這個中間件所處理,我們得到的返回值都是這個中間件調用Response
對象,返回的 string 類型的字元串。 返回的值是純文本而不是 html。 我們可以通過檢查頁面源代碼來確認這一點。 可以看到,我們在源代碼中沒有任何 html 標記。 只是純文本。
即使您現在創建一個為52abp.html
的文件,並且您在請求中包含該文件的路徑,我們的應用程式也無法返回該靜態文件。 這是因為,目前我們的請求處理管道沒有可以提供靜態文件的中間件,如html文件,圖像,CSS和JavaScript文件
。 在後面的課程中,我們將添加所需的中間件以便能夠提供靜態文件。
研究下 Configure()方法中的代碼。
app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World!");
});
代碼說明:
- 我們調用 Run() 方法添加中間件到請求處理管道中。
- 如果將滑鼠懸停在 Run()方法上,則可以從 智能提示中看到
Run()
方法是作為IApplicationBuilder
介面的擴展方法實現的。這就是我們能夠在IApplicationBuilder
對象應用程式上調用此Run()
方法的原因。 - 我們傳遞給
Run()
方法的參數是一個RequestDelegate
,我們可以從智能提示中看到它。 RequestDelegate
是一個作為HttpContext
對象的參數委托。- 通過這個
HttpContext
對象,中間件可以訪問傳入的 http 請求和傳出的 http 響應。 - 目前,我們使用
lambda
將請求,它通過委托內聯的方式作為匿名方法傳遞,所以很多人都說 lambda 表達式是一種特殊的委托。如果你聽不明白 lambda 表達式,委托,及內聯,你可以參考學習:- 委托(delegate)
- Lambda 簡介 ,或者等我錄製 C#的基礎視頻吧。
- 使用
Run()
擴展方法,我們只能將一個終端中間件
添加到請求管道。 終端中間件
是我們之前已經說到過,他會使管道短路,不會去調用下一個中間件。
研究下麵的代碼
app.Run(async (context) =>
{
await context.Response.WriteAsync("從第一個中間件中列印Hello World");
});
app.Run(async (context) =>
{
await context.Response.WriteAsync("從第二個中間件中列印Hello World");
});
- 我們使用
Run()
方法註冊了 2 個中間件。 - 運行此項目時,我們只看到第一個中間件的響應,有返回值。
- 我們沒有看到第二個中間件的響應。
- 這是因為,使用
Run()
方法註冊的中間件無法調用管道中的下一個中間件。 - 因此,我們使用
Run()
方法註冊的中間件是終端中間件
如果您希望中間件能夠調用管道中的下一個中間件,則使用Use()
方法註冊中間件,如下所示。
app.Use(async (context, next) =>
{
await context.Response.WriteAsync("從第一個中間件中列印Hello World");
await next();
});
app.Run(async (context) =>
{
await context.Response.WriteAsync("從第二個中間件中列印Hello World");
});
註意,Use()
方法有 2 個參數。第一個參數是HttpContext
上下文對象,第二個參數是Func
類型,即它是代表管道中下一個中間件的通用委托。
我們再看看以下代碼
public void Configure(IApplicationBuilder app, IHostingEnvironment env,
ILogger<Startup> logger)
{
app.Use(async (context, next) =>
{
logger.LogInformation("MW1:傳入請求");
await next();
logger.LogInformation("MW1:傳出響應");
});
app.Use(async (context, next) =>
{
logger.LogInformation("MW2: 傳入請求");
await next();
logger.LogInformation("MW2: 傳出響應");
});
app.Run(async (context) =>
{
await context.Response.WriteAsync("MW3: 處理請求並生成響應");
logger.LogInformation("MW3: 處理請求並生成響應");
});
}
ILogger < Startup >
被註入到Configure()
方法中Main()
方法調用的CreateDefaultBuilder()
配置日誌記錄- 您可以通過查看在 GitHub 的源代碼驗證這一點 :https://github.com/aspnet/MetaPackages/blob/release/2.2/src/Microsoft.AspNetCore/WebHost.cs
- 檢查方法
ConfigureLogging()
,* 您會發現,ILogger 配置了Console,Debug和EventSource
三種. - 我們使用
依賴註入
的方式將ILogger
記錄到系統中。 - 如果使用.NET Core CLI 運行項目,則可以在“控制台”視窗中查看記錄的信息
- 如果直接從
Visual Studio
運行項目,則可以在輸出視窗中
查看記錄的信息。從輸出視窗的下拉列表中選擇 ASP.NET Core Web Server。 - 您將看到,信息按以下順序記錄
- MW1:傳入請求
- MW2:傳入請求
- MW3:處理請求並生成響應
- MW2:傳出響應
- MW1:傳出響應
現在將上面的輸出與微軟的官方文檔中的下圖集合起來,是不是就清晰明瞭啊。吐槽下,微軟的文檔有粗糙。
-
請記住,asp.net Core 中的中間件可以訪問傳入請求和傳出響應
-
請求先到達
Middleware1
,它記錄**(MW1:傳入請求)**,因此我們首先看到此消息。 -
然後
Middleware1
調用next()
。next()
會調用管道中的Middleware2
。 -
Middleware2
記錄**(MW2:傳入請求)**。 -
然後
Middleware2
會調用next()
再調用Middleware3
. -
Middleware3
處理請求並生成響應。因此,我們看到的下一條消息是(MW3:處理請求並生成響應)
-
此時管道開始逆轉。
-
此時控制權將,交回到
Middleware2
,並將Middleware3
生成的響應傳遞給它。Middleware2
記錄**(MW2:傳出響應)**,這是我們接下來看到的。 -
最後,
Middleware2
將控制權交給Midleware1
。 -
Middleware1
記錄 (MW1: 傳出響應), 這是我們最後看到的。
請求處理管道的中 3 個非常重要的知識點:
- 所有的
請求
都會在每個中間件組件調用next()方法
之前觸發。請求
按照圖中箭頭的所示方向,依次穿過所有管道。 - 當中間件處理請求並產生響應時,請求處理流程在管道中開始反向傳遞。
- 所有的
響應
都會在每個中間件組件調用next()方法
之前觸發。響應
按照圖中箭頭的所示方向,依次穿過所有管道。
小結
Response 為抽象類
亂碼問題
context.Response.ContentType = "text/plain; charset=utf-8";
歡迎添加個人微信號:Like若所思。
歡迎關註我的公眾號,不僅為你推薦最新的博文,還有更多驚喜和資源在等著你!一起學習共同進步!