ASP.Net Core MVC基礎(chǔ)系列之中間件
上一節(jié)我們介紹了服務(wù)注冊和基本的管道執(zhí)行流程, 并且講到了中間件, 這一節(jié)我們就來詳細(xì)談?wù)勚虚g件這個東西
講中間件, 其實(shí)就是講Startup類里面的ConfigureServices 和Configure 這兩個方法
在程序啟動類Program 中, 我們在CreateWebHostBuilder 方法中調(diào)用了UseStartup方法, 里面用泛型注入了 Startup 類, 那程序就會自動實(shí)例化這個類, 并且去執(zhí)行它里面的ConfigureServices 和Configure 這兩個方法. 我們就可以做很多配置操作
首先調(diào)用的第一個方法當(dāng)然就是構(gòu)造函數(shù), 這里沒有沒有, 我們不說, 然后就是ConfigureServices 方法. 這個方法上一節(jié)已經(jīng)使用過了, 在這個方法里面, 我們可以注冊一些服務(wù)或者我們叫自定義服務(wù). 注冊完服務(wù), 我們就可以通過依奈注入的方式在其它地方使用這些服務(wù).
然后再執(zhí)行的方法就是Configure 這個方法. 我們能看到Configure 方法默認(rèn)的第一個參數(shù)是IApplicationBuilder 接口, 可以理解為整個程序的根, 我們通過這個接口對象, 可以精確的配置獲取啟用我們的中間件, 使我們的各種中間件組合起來, 形成一個完美的Web應(yīng)用程序, 去處理我們的HTTP請求并且做出對應(yīng)的響應(yīng)等等.
講之前, 我們先把
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}這幾行代碼注釋掉, 待會再用, 再去解釋這個是干嘛用的, 為什么要加個if, 這里先注釋掉
我們看這個代碼
app.Run(async (context) =>
{
var msg = welcome.GetWelcomMsg();
await context.Response.WriteAsync(msg);
});這個app.Run方法, 可以理解為我們自己寫的一個中間件, 它什么都不干, 就是為響應(yīng)輸出一個字符串. 其實(shí)這是新建項(xiàng)目默認(rèn)生成的.
在真實(shí)的項(xiàng)目中, 我們基本上不會使用app.Run這個方法去處理我們的請求, 因?yàn)槲易龅氖虑檫h(yuǎn)遠(yuǎn)比輸出一個字符串復(fù)雜很多.
在實(shí)際開發(fā)中, 我們通常使用的中間件都是app.Usexxxx開頭的, 才能組成一個完成的Web項(xiàng)目, 比如 app.UseMvc / app.UseStaticFiles等等這些方法去啟用系統(tǒng)自帶的中間件獲取別的第三方中間件.
我們這里啟用個ASP.Net Core MVC自帶的彩蛋中間件吧, 代碼為:app.UseWelcomePage(); 啟用默認(rèn)的MVC歡迎頁面. 我們F5執(zhí)行.

我們能夠正??吹匠霈F(xiàn)了一個頁面, 而不是簡單的一個字符串的輸出了
然后我們嘗試改變一下地址欄, 隨便寫個什么, 可以發(fā)現(xiàn), 我們隨便怎么輸入地址, 都是進(jìn)入到歡迎頁, 如圖 :

到這里, 我們就可以發(fā)現(xiàn), 這個"彩蛋"中間件的"優(yōu)先級"還是很高的, 在ASP.Net Core MVC發(fā)現(xiàn)你使用了這個中間件的時候, 他就不會執(zhí)行后面的東西了, 或者說不會執(zhí)行后面的中間件了.
還有呢, 在我們使用中間件的時候, 或者說是在調(diào)用app.Usexxxx方法的時候, 一般來說, 這個方法都會接受一個對象參數(shù), 這個參數(shù)可以對這個中間件進(jìn)行一些配置, 下面我們嘗試配置一下"彩蛋"中間件, 告訴大家中間件是怎么配置的. 代碼是這樣的
app.UseWelcomePage(new WelcomePageOptions
{
Path = "/welcome"
});都能看到, 這里是為"彩蛋"配置了一個地址(路徑), 現(xiàn)在我們F5看看效果
會發(fā)現(xiàn)網(wǎng)頁輸出是個字符串, 那我們在地址后面加上 /welcome 再看看, 可以發(fā)現(xiàn)能正常出現(xiàn)"彩蛋"了, 說明這個配置是有效的.
當(dāng)然我的目的不是講這個"彩蛋"怎么使用, 而是給大家介紹中間件怎么使用, 怎么去配置中間件, 基本上所有的中間件都是這個使用方式和配置方式.
既然說到了這里, 那我們來說說 app.Use 這個方法. 這個方法怎么說呢, 就是它比較"底層", 因?yàn)閍pp.Use里面的參數(shù)類型是RequestDelegate , 也就是當(dāng)前請求對象的委托, 相對比較"底層", 可以說是當(dāng)前請求管道的"原型". 我們來寫一些代碼試試吧.
app.Use(next =>
{
return async context =>
{
if (context.Request.Path.StartsWithSegments("/first"))
{
await context.Response.WriteAsync("First");
}
else
{
await next(context);
}
};
});我們寫的代碼如上, 它的意思就是: 當(dāng)前地址是/first 的時候, 輸出 First 這個字符串, 否則就不管, 繼續(xù)往下執(zhí)行, 去執(zhí)行別的中間件, 我們運(yùn)行看看效果. 可以發(fā)現(xiàn), 默認(rèn)輸出的是 你好, .Net Core 2.2, 當(dāng)我們把地址后面加上/first 的時候, 輸出的就是First, 如圖:

我們再輸入地址 /welcome 的是, 可以看到"彩蛋"正常出現(xiàn)了, 可以看到, 我們的Use方法是正常的
在實(shí)際開發(fā)過程中, 我們很少直接使用app.Use方法去處理我們的底層請求的, 這里只是簡單介紹了這個方法, 以及它能干什么.
知道app.Use是干什么的, 那就把上面的app.Use方法刪掉吧, 或者注釋掉, 我們下面的教程不會用的.
接下來, 我們干點(diǎn)壞事, 我們在 app.Run 方法里面手動報(bào)個異常出來, 代碼如下:
app.Run(async (context) =>
{
throw new Exception();
var msg = welcome.GetWelcomMsg();
await context.Response.WriteAsync(msg);
});我們執(zhí)行項(xiàng)目, 會看到出現(xiàn)了500錯誤, Chrome瀏覽器是這樣的, 其它瀏覽器可能不一樣

但是我們不希望這樣, 我們希望我們能看到異常的詳細(xì)信息, 這時候, 我們就需要啟用一個異常中間件, 就是我們上面注釋掉的那個 iif (env.IsDevelopment()) 的代碼, 我們把它啟用起來, 那么我們的Configure 方法里面代碼就是這樣的, 如圖:

然后我們再F5運(yùn)行項(xiàng)目, 就是這樣的了, 如圖:

我們的異常就很明顯了, 很好排查錯誤
至于為什么加個if (env.IsDevelopment()), 這個代碼一看就知道意思了吧, 就是當(dāng)前環(huán)境是開發(fā)環(huán)境的時候, 才啟用這個異常顯示中間件
因?yàn)槲覀冎幌M陂_發(fā)或者調(diào)試的時候, 才顯示異常的詳細(xì)信息, 別的環(huán)境不顯示, 這樣安全一些, 如果不加這個 if , 會在任何環(huán)境都會顯示詳細(xì)的錯誤信息, 這樣可能會給我們的Web應(yīng)用帶來安全隱患.
所以, 我們再加個else , 在else里面啟用一個別的中間件, 代碼如下:
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler();
}這樣我們不是在開發(fā)環(huán)境的時候, 發(fā)送異常就是這樣的:

不至于暴露一些敏感的信息
我們發(fā)現(xiàn)這個啟動異常頁面中間件的代碼寫在最上面, 那我們把它移動到Configure 方法的最后面, 會怎么樣呢 ? 我們試試, 代碼如圖:

可以看到, 我把異常頁面中間件移動到最后面啟用了, 我們F5運(yùn)行項(xiàng)目, 會發(fā)現(xiàn), 瀏覽器不出先異常頁面了, 而是直接 500 錯誤.
可以知道, 中間件的啟用順序是有依奈關(guān)系和順序的, 不能隨便啟用的, 需要在正確的位置啟用對應(yīng)的中間件, 如果順序錯了, 可能會導(dǎo)致中間件失效, 如果你在開發(fā)過程中, 啟用了某個中間件, 但是它卻沒效果, 可以使用該思路進(jìn)行排查.
到這里, 這一節(jié)就結(jié)束了, 到目前為止, 我們的Web應(yīng)用功能很簡單, 就是輸出一個字符串和啟用了一個"彩蛋".
我們還講到了"環(huán)境", 比如上面的if (env.IsDevelopment()) 判斷是不是開發(fā)環(huán)境, 那么怎么改變這個環(huán)境, 讓我們在開發(fā)或者試運(yùn)行和運(yùn)營環(huán)境切換, 加載不同的配置和啟用不同的中間件
到此這篇關(guān)于ASP.Net Core MVC基礎(chǔ)系列之中間件的文章就介紹到這了。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
.Net行為型設(shè)計(jì)模式之觀察者模式(Observer)
這篇文章介紹了.Net行為型設(shè)計(jì)模式之觀察者模式(Observer),文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-05-05
詳解ABP框架中領(lǐng)域?qū)拥念I(lǐng)域事件Domain events
ABP是基于ASP.NET框架之上的Web開發(fā)框架(GitHub:https://github.com/aspnetboilerplate),這篇我們來詳解ABP框架中領(lǐng)域?qū)拥念I(lǐng)域事件Domain events,需要的朋友可以參考下2016-06-06
ASP.NET2.0+SQL Server2005構(gòu)建多層應(yīng)用
ASP.NET2.0+SQL Server2005構(gòu)建多層應(yīng)用...2006-12-12
ASP.Net頁面生命周期與Page_Load方法的工作原理介紹
這篇文章介紹了ASP.Net頁面生命周期與Page_Load方法的工作原理,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-05-05

