您好,登錄后才能下訂單哦!
今天小編給大家分享一下ASP.NET Core中間件與管道的概念是什么的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
在ASP.NET Core中,針對HTTP請求采用pipeline也就是通常說的管道方式來處理,而管道容器內可以掛載很多中間件(處理邏輯)“串聯”來處理HTTP請求,每一個中間件都有權決定是否需要執行下一個中間件,或者直接做出響應。這樣的機制使得HTTP請求能夠很好的被層層處理和控制,并且層次清晰處理起來甚是方便。 示意圖如下:
為了再次說明管道和中間件的概念,舉一個官方給出的權限驗證的例子,中間件A,B分別按順序掛載在管道容器中,A為權限驗證中間件,只有通過A的權限驗證才能執行B,如果沒有通過A的驗證,A有權中斷管道處理直接返回相應的錯誤提示例如401等。這樣必須由上一節點來調用的串行遞歸執行方式就是pipeline,而每一個節點就是中間件或者叫中間組件。現在我們來看看如何在ASP.NET Core中使用中間件和管理自己的HTTP管道
在了解中間件之前我們需要先知道Startup這個類具體運作方式,我們以下面這段代碼為例:
/// <summary> /// web宿主的入口類 /// </summary> public class Startup { //加入服務項到容器, 這個方法將會被runtime調用 public void ConfigureServices(IServiceCollection services) { } /// <summary> /// 配置HTTP請求管道 /// </summary> /// <param name="app">被用于構建應用程序的請求管道 只可以在Startup中的Configure方法里使用</param> /// <param name="env">提供了訪問應用程序屬性,如環境變量</param> /// <param name="loggerFactory">提供了創建日志的機制</param> public void Configure(IApplicationBuilder app,IHostingEnvironment env,ILoggerFactory loggerFactory) { loggerFactory.AddConsole(); if (env.IsDevelopment()) //根據配置的環境為開發環境,則會配置拋出異常錯誤界面 { app.UseDeveloperExceptionPage(); //拋出詳細的異常錯誤界面 } //管道斷路 app.Run(async (context) => { await context.Response.WriteAsync("Hello World!"); }); } }
可以看到 Startup.cs 內有兩個方法,一個是用來配置接口服務到管道容器中的ConfigureServices, 一個是用來配置管道中間件的Configure。
為什么必須是這兩個方法名?
其實這兩個方法名并不是規定死的,但也不是任意規定的,他是根據容器的環境變量來判斷的,這里先給出官方文檔《多環境下工作》。
我們可以在文檔中了解到,Core使用“ASPNETCORE_ENVIRONMENT”字段來描述當前運行環境名稱這就是上文中提到的環境配置,官方預設了3個環境名分別是Development(開發環境), Staging(測試環境), Production(生產環境),如果您使用的是VSCode您可以在.vscode文件夾下的launch.json中找到“ASPNETCORE_ENVIRONMENT”字段,可以發現默認情況下是Development,那說這些到底有什么用呢?
在Startup中規定,配置服務和中間件兩個方法可以根據環境名稱來命名和選擇調用,命名規則為ConfigureServices{ENVIRONMENT}和Configure{ENVIRONMENT}。如ASPNETCORE_ENVIRONMENT = “Development” 則ConfigureServices和Configure 可以寫成ConfigureServicesDevelopment 和ConfigureDevelopment ,其他也是如此。這樣就可以通過配置ASPNETCORE_ENVIRONMENT 來決定該調用哪一個配置方法了。
ConfigureServices和Configure是什么環境下的呢?
ConfigureServices和Configure就好像Switch 語句中的 default一樣的道理,如果沒有找到任何符合環境名的方法名,就會執行調用這兩個方法。如配置了Development,但卻沒有給出ConfigureServicesDevelopment ,這時就會執行ConfigureServices,如果都沒有就會拋出異常。
必須設置成預設環境名嗎?
環境名配置的參數名不必是預設值,你可以自己寫一個,比如LogEnv等等。
接下來我們看一下實現的代碼:
/// <summary> /// web宿主的入口類 /// </summary> public class Startup { //加入服務項到容器, 這個方法將會被runtime調用 public void ConfigureServices(IServiceCollection services) { } /// <summary> /// Log環境下配置HTTP請求管道 /// </summary> /// <param name="app"></param> public void ConfigureLogHelp(IApplicationBuilder app){ app.Run(async (context) => { await context.Response.WriteAsync("Hello World - ConfigureLogHelp"); }); } /// <summary> /// 開發環境下配置HTTP請求管道 /// </summary> /// <param name="app"></param> public void ConfigureDevelopment(IApplicationBuilder app){ app.Run(async (context) => { await context.Response.WriteAsync("Hello World - ConfigureDevelopment"); }); } /// <summary> /// 默認情況下配置HTTP請求管道 /// </summary> /// <param name="app">被用于構建應用程序的請求管道。只可以在 Startup 中的 Configure 方法里使用</param> /// <param name="env">提供了訪問應用程序屬性,如環境變量</param> /// <param name="loggerFactory">提供了創建日志的機制</param> public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { //管道斷路 app.Run(async (context) => { await context.Response.WriteAsync("Hello World!"); }); }
當ASPNETCORE_ENVIRONMENT = “Development”
當ASPNETCORE_ENVIRONMENT = “LogHelp”
這樣做的好處就是你可以寫自己的測試配置而不會影響到其他人或者開發過程。當然環境的作用還在于前端應該引用什么樣的CSS和JS,關于這些我們之后在MVC的章節再來討論, 想了解的博友可以看官方文檔
說完環境配置和Startup的關系,我們回來接著聊管道的事情,現在我們來說說Configure{ENVIRONMENT}一下Configure簡稱這個方法。
Configure這個方法是用于配置中間件到中管道容器(IApplicationBuilder),所以這個方法必須要包含一個IApplicationBuilder參數用來接受管道容器,方便開發者配置。當然他還可以接受其他的可選參數供開發者使用如下:
(注:下圖來源于ASP.NET Core中文文檔)
需要提一下的是,剛剛我們上文中說的環境名在IHostingEnvironment中可以獲取,對于預設值官方還做了判斷封裝,當然你可以重構它來封裝自己的環境名判斷。
HTTP管道容器由三個擴展的方法來控制中間件的路由、掛載等等,分別是Run, Map, User。
a.Run方法會使得可以使管道短路,顧名思義就是終結管道向下執行不會調用next()委托,所以Run方法最好放在管道的最后來執行,如下面的代碼:
/// <summary> /// 開發環境下配置HTTP請求管道 /// </summary> /// <param name="app"></param> public void ConfigureDevelopment(IApplicationBuilder app){ app.Run(async (context) => { await context.Response.WriteAsync("Hello World - ConfigureDevelopment"); }); app.Run(async (context) => { await context.Response.WriteAsync("Hello World - ConfigureDevelopment 不會被執行"); }); }
執行結果:
b.Use不會主動短路整個HTTP管道,但是也不會主動調用下一個中間件,必須自行調用await next.Invoke(); 如果不使用這個方法去調用下一個中間件那么Use此時的效果其實和Run是相同的,我們來看正常的代碼:
/// <summary> /// 開發環境下配置HTTP請求管道 /// </summary> /// <param name="app"></param> public void ConfigureDevelopment(IApplicationBuilder app){ var order =""; app.Use(async (context, next) => { order = $"{order}|Use start"; await next.Invoke(); order = $"{order}|Use end"; }); app.Run(async context => { await context.Response.WriteAsync($"{order}|Run ext"); }); }
執行結果如下:
可以看到,Use end并沒有被執行到,因為在調用下一個中間件時采用了Run,管道被終止了。
再來看看如果不顯式調用next.Invoke()時的代碼:
/// <summary> /// 開發環境下配置HTTP請求管道 /// </summary> /// <param name="app"></param> public void ConfigureDevelopment(IApplicationBuilder app){ var order =""; app.Use(async (context, next) => { order = $"{order}|Use start"; //去掉顯示調用下一個中間件 //await next.Invoke(); order = $"{order}|Use end"; await context.Response.WriteAsync(order); }); app.Run(async context => { await context.Response.WriteAsync($"{order}|Run ext"); }); }
其結果如下:
可以發現Run這個中間件并沒有被執行,而只是單純的執行了Use這個中間件。所以說 在不顯式調用下一個中間件的情況下,效果和Run時一樣的會使管道短路。
c.Map可以根據提供的URL來路由中間件,如下代碼判斷URL中訪問"/test"時就會執行某個中間件邏輯:
/// <summary> /// 開發環境下配置HTTP請求管道 /// </summary> /// <param name="app"></param> public void ConfigureDevelopment(IApplicationBuilder app){ app.Map("/test", HandleMapTest); } /// <summary> /// maptest 處理方法 /// </summary> public void HandleMapTest(IApplicationBuilder app){ app.Run(async (context) => { await context.Response.WriteAsync("HandleMapTest Handler"); }); }
結果如下:
如果訪問/test就會執行相應的中間件,反之則不會執行。
MapWhen是Map的一個條件判斷的擴展方法,可以通過它來判斷某個條件適合的時候執行某一個中間件,如:當攜帶某一個參數名稱時,執行某一個中間件或者反之,代碼如下:
/// <summary> /// 開發環境下配置HTTP請求管道 /// </summary> /// <param name="app"></param> public void ConfigureDevelopment(IApplicationBuilder app){ app.MapWhen(context => { return context.Request.Query.ContainsKey("username"); }, HandleUserName); app.Run(async context => { await context.Response.WriteAsync("default ext"); }); } /// <summary> /// /// </summary> public void HandleUserName(IApplicationBuilder app){ app.Run(async context => { await context.Response.WriteAsync("UserName Map"); }); }
結果如下:
以上就是“ASP.NET Core中間件與管道的概念是什么”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。