圖例
詳細說明:
一、啟動順序
1、程序啟動,運行main方法
2、創建web服務器,啟動startup類
3、執行ConfigureServices,為程序配置可供重用的服務
4、執行Configure,配置中間件處理請求和響應
二、中間件
什么是中間件
中間件是用於組成應用程序管道來處理請求和響應的組件。管道內的每一個組件都可以選擇是否將請求交給下一個組件、並在管道中調用下一個組件之前和之后執行某些操作。請求委托被用來建立請求管道,請求委托處理每一個 HTTP 請求。 請求委托通過使用 IApplicationBuilder 類型的 Run、Map 以及 Use 擴展方法來配置,並在 Startup 類中傳給 Configure 方法 。每個單獨的請求委托都可以被指定為一個內嵌匿名方法,或其定義在一個可重用的類中。這些可重用的類被稱作 中間件 或 中間件組件。每個位於請求管道內的中間件組件負責調用管道中下一個組件,或適時短路調用鏈。 Migrating HTTP Modules to Middleware 解釋了請求管道在 ASP.NET Core 和之前版本之間的區別,並提供了更多中間件樣例。
用 IApplicationBuilder 創建中間件管道 ASP.NET 請求管道由一系列的請求委托所構成,它們一個接着一個被調用,如圖所示(該執行線程按黑色箭頭的順序執行):
每個委托在下一個委托之前和之后都有機會執行操作。任何委托都能選擇停止傳遞到下一個委托,轉而自己處理該請求。這被叫做請求管道的短路,而且是一種有意義的設計,因為它可以避免不必要的工作。比方說,一個授權(authorization)中間件只有在通過身份驗證之后才調用下一個委托,否則它就會被短路並返回 “Not Authorized” 的響應。異常處理委托需要在管道的早期被調用,這樣它們就能夠捕捉到發生在管道內更深層次出現的異常了。
Run,Map 與 Use 你可以使用 Run、Map 和 Use 配置 HTTP 管道。Run 方法將會短路管道(因為它不會調用 next 請求委托)。因此,Run 應該只能在你的管道尾部被調用。Run 是一種慣例,有些中間件組件可能會暴露他們自己的 Run[Middleware] 方法,而這些方法只能在管道末尾處運行。下面這兩個中間件等價的,其中有用到 Use 的版本沒有使用 next 參數:
public void ConfigureEnvironmentOne(IApplicationBuilder app) { app.Run(async context =>//手工高亮 { await context.Response.WriteAsync("Hello from " + _environment); }); }public void ConfigureEnvironmentTwo(IApplicationBuilder app)
{
app.Use(async (context, next) =>//手工高亮
{
await context.Response.WriteAsync("Hello from " + _environment);
});
}
Map
擴展方法用於匹配基於請求路徑的請求委托。Map
只接受路徑,並配置單獨的中間件管道的功能。在下例中,任何基於路徑 /maptest
的請求都會被管道中所配置的 HandleMapTest
方法所處理。
private static void HandleMapTest(IApplicationBuilder app) { app.Run(async context => { await context.Response.WriteAsync("Map Test Successful"); }); }public void ConfigureMapping(IApplicationBuilder app)
{
app.Map("/maptest", HandleMapTest);//手工高亮
}
編寫中間件
對於更復雜的請求處理功能,推薦在自己的類中實現中間件,並暴露 IApplicationBuilder
擴展方法,這樣就能通過 Configure
方法來被調用。之前演示的簡易日志中間件就能被轉換為一個中間件類(middleware class):只要在其構造函數中獲得下一個 RequestDelegate
並提供一個 Invoke
方法,如下所示:
中間件遵循 顯式依賴原則 並在其構造函數中暴露所有依賴項。中間件能夠利用到 UseMiddleware 擴展方法的優勢,直接通過它們的構造函數注入服務,就像下面的例子所示。依賴注入服務是自動完成填充的,擴展所用到的 params
參數數組被用於非注入參數。
public static class RequestLoggerExtensions { public static IApplicationBuilder UseRequestLogger(this IApplicationBuilder builder) { return builder.UseMiddleware<RequestLoggerMiddleware>(); } }
通過使用擴展方法和相關中間件類,Configure
方法變得非常簡潔和高可讀性。
盡管 RequestLoggerMiddleware
在其構造函數中需要 ILoggerFactory
參數,但無論是 Startup
類還是 UseRequestLogger
擴展方法都不需要顯式依賴之。相反,它將自動地通過內置的 UseMiddleware<T>
來執行依賴注入以提供之。
測試中間件(通過給 LogMiddleware
設置 Hosting:Environment
環境變量)會輸出下圖的結果(當時用了 WebListener 時):
注意
UseStaticFiles 擴展方法(該方法會創建 StaticFileMiddleware)同樣也使用了 UseMiddleware<T>
。所以除了 StaticFileOptions
參數被傳入之外,構造函數的其他參數都由 UseMiddleware<T>
和依賴注入所提供。
--