AspNetCore中的中間件詳解
1 什么叫做中間件?
ASP.NET Core處理請求的方式看做是一個管道,中間件是組裝到應(yīng)用程序管道中用來處理請求和響應(yīng)的組件。通常是一個可重用的類方法
每個中間件可以:
(1)選擇是否將請求傳遞給管道中的下一個組件。
(2)可以在調(diào)用管道中的下一個組件之前和之后執(zhí)行業(yè)務(wù)邏輯。
其中關(guān)于請求管道配置的一個重要方法在startup中的Configure(IApplicationBuilder app, IWebHostEnvironment env)方法??捎肬se、Map、Run方法來配置需要使用的中間件。通常使用
IApplicationBuilder的拓展方法來配置請求管道,加入指定的中間件。
IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware);
中間件類的本質(zhì)其實是委托類
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { //判斷是否為開發(fā)環(huán)境 if (env.IsDevelopment()) { //使用異常開發(fā)頁面中間件 app.UseDeveloperExceptionPage(); } //靜態(tài)文件中間件 app.UseStaticFiles(); //HTTP請求轉(zhuǎn)HTTPS請求 app.UseHttpsRedirection(); //身份驗證 app.UseAuthentication(); //相較于netcore2來說,Routing 中間件是拆分出來的,原來是屬于MVC中間件的一部分 app.UseRouting(); //端點中間件,請求處理路徑,結(jié)合Routing中間件一起使用的 app.UseEndpoints(endpoints => { //當請求"/"時,響應(yīng)輸出HelloWorld【可通過lamda表達式進行配置】 endpoints.MapGet("/", async context => { await context.Response.WriteAsync("Hello World!"); }); //請求路徑匹配到 /home/index/1 這種路徑時,將會到指定的handler處理器上,默認會處理到 endpoints.MapControllerRoute("default","/{controller=home}/{action=index}/{id?}"); }); }
2 請求短路與中間件順序
請求會按照順序依次經(jīng)過每個加入管道的中間件,值得注意的是,中間件可以決定是否將請求交給下一個委托,當中間件拒絕將請求傳遞到下一個中間件時,叫做請求短路,可以避免不必要的工作。
中間件的執(zhí)行與調(diào)用的順序有關(guān),在響應(yīng)式以相反的順序返回。請求在每一步都有可能短路,所以需要正確的添加中間件,如異常處理的中間件,需要放在請求管道的前面,這樣就可以一開始捕獲異常,以及后面中間件中可能發(fā)生的異常,做出返回處理。
3 中間件配置方法Use、Run、Map
ASP.NET 中的核心請求管道是通過一個個請求委托串聯(lián)而來的,具體是通過IApplicationBuilder的Use、Run、Map方法來實現(xiàn)的。
在講解中間件配置方法之前,需要了解什么是RequestDelegate、和代碼語言描述的中間件Func<RequestDelegate, RequestDelegate> middleware
//一個能處理請求的方法 public delegate Task RequestDelegate(HttpContext context); //中間件原生定義,委托,輸入是一個RequestDelegate,輸出也是一個RequestDelegate, Func<RequestDelegate, RequestDelegate> middleware = new Func<RequestDelegate, RequestDelegate>((RequestDelegate requestdelegate) => { return new RequestDelegate(async (context) => { await context.Response.WriteAsync("接收1個帶RequestDelegate類型的參數(shù),返回RequestDelegate類型的委托"); }); }); // 上述中間件的定義代碼可根據(jù)lamda表達式規(guī)則進行縮寫 Func<RequestDelegate, RequestDelegate> middleware = new Func<RequestDelegate, RequestDelegate>((RequestDelegate requestdelegate) => { return new RequestDelegate(async (context) => { await context.Response.WriteAsync("接收1個帶RequestDelegate類型的參數(shù),返回RequestDelegate類型的委托"); }); }); Func<RequestDelegate, RequestDelegate> middleware = (request=>{ return new RequestDelegate(async (context) => { await context.Response.WriteAsync("接收1個帶RequestDelegate類型的參數(shù),返回RequestDelegate類型的委托"); }); });
3.1Use 方法配置中間件
//增加中間件到請求管道中 IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware);
Use 擴展可以使用兩個重載:
一個重載采用 HttpContext 和 Func < Task >。 不使用任何參數(shù)調(diào)用 Func< Task >。
app.Use(async (context, next) => { await context.Response.WriteAsync(" Rquest The first middleware"); //調(diào)用下一個中間件 await next.Invoke(); await context.Response.WriteAsync(" Response The first middleware"); });
另一個重載采用 HttpContext 和 RequestDelegate。 通過傳遞 HttpContext 調(diào)用 RequestDelegate。
優(yōu)先使用后面的重載,因為它省去了使用其他重載時所需的兩個內(nèi)部每請求分配。
app.Use(next => { return new RequestDelegate(async context => { await context.Response.WriteAsync(" Rquest The first middleware"); await next.Invoke(context); await context.Response.WriteAsync(" Response The first middleware"); }); } );
上面兩種方法實現(xiàn)的功能一致。值得注意的是,next參數(shù)表示管道中的下一個中間件。通過不調(diào)用下一個中間件,會導(dǎo)致請求短路或中斷,所以需要謹慎的選擇是否需要調(diào)用下一個中間件。
3.2Run 方法配置中間件
public static void Run(this IApplicationBuilder app, RequestDelegate handler);
Run 方法配置請求管道時,會使得請求管道短路,因為它不調(diào)用下一個請求。因此Run方法一般只在管道的底部使用。
app.Run( async context=> { await context.Response.WriteAsync(" Rquest The final middleware"); });
3.2Map 方法配置中間件
//pathMatch 請求路徑匹配字符串 //configuration 符合匹配規(guī)則時采取的 請求處理邏輯. //configuration 是一個無返回,請求參數(shù)類型為 IApplicationBuilder的回調(diào)函數(shù)。 public static IApplicationBuilder Map(this IApplicationBuilder app, PathString pathMatch, Action<IApplicationBuilder> configuration);
Map 方法是一種可以基于請求路徑的不同來配置分支中間件。
app.Map("/secondturl", appBuilder => { appBuilder.Run(async context => { await context.Response.WriteAsync(" the request'url is secondturl" + "\n"); }); });
且可以在嵌套使用Map方法去配置分支中間件
4 自定義中間件
雖然中間件的本質(zhì)是一個Func<RequestDelegate, RequestDelegate> middleware 對象,
中間件的類型可分為兩種,下面自定義實現(xiàn)以及記錄請求IP地址的中間件
弱類型中間件
(1) 定義Ip中間件
public class RequestIpMiddleware { private readonly RequestDelegate requestDelegate; public RequestIpMiddleware(RequestDelegate requestDelegate) { this.requestDelegate = requestDelegate; } public async Task Invoke(HttpContext context) { context.Response.WriteAsync("The Request Ip is " + context.Request.HttpContext.Connection.RemoteIpAddress.ToString()+"\n"); //調(diào)用下一個請求中間件 await requestDelegate.Invoke(context); } }
(2)增加Use的拓展方法
/// <summary> /// 調(diào)用中間件的擴展方法 /// </summary> public static class MiddlewareExtensions { /// <summary> ///this 關(guān)鍵字不能省略 /// </summary> /// <param name="app"></param> /// <returns></returns> public static IApplicationBuilder UseIpMiddleware( this IApplicationBuilder app ) { return app.UseMiddleware<RequestIpMiddleware>(); } }
(3)Configure方法中使用該中間件
app.UseIpMiddleware();
強類型中間件
可以在Use方法中調(diào)用這個匿名內(nèi)部類,但是最好是將中間件定義成一個強類型,利于閱讀,且符合編程習(xí)慣。
IApplicationBuilder 提供了一種拓展方法來配置強類型的中間件
public static IApplicationBuilder UseMiddleware<TMiddleware>(this IApplicationBuilder app, params object[] args);
/// <summary> /// 自定義中間件 /// </summary> public class IPMiddleware : IMiddleware { /// <summary> /// IMiddleware接口定義了唯一的InvokeAsync方法,用來實現(xiàn)對請求的處理。 /// </summary> /// <param name="context"> 當前請求上下文</param> /// <param name="next">下一個請求requestDelegate</param> /// <returns></returns> public Task InvokeAsync(HttpContext context, RequestDelegate next) { //獲取請求的IP var ip = context.Request.HttpContext.Connection.RemoteIpAddress.ToString(); context.Response.WriteAsync("IP is "+ip+"\n"); //調(diào)用下一個中間件 return next.Invoke(context); } }
值得注意的是在使用這個中間件時,需要將當前中間件注入到容器中,否則請求管道中的這個中間件無法生效。
到此這篇關(guān)于AspNetCore中的中間件詳解的文章就介紹到這了,更多相關(guān)AspNetCore中間件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
ASP.NET Core Zero使用Power Tool工具
這篇文章介紹了ASP.NET Core Zero使用Power Tool工具的方法,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-02-02.Net彈性和瞬態(tài)故障處理庫Polly實現(xiàn)執(zhí)行策略
這篇文章介紹了.Net彈性和瞬態(tài)故障處理庫Polly實現(xiàn)執(zhí)行策略的方法,文中通過示例代碼介紹的非常詳細。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-06-06asp.net 關(guān)于字符串內(nèi)范圍截取的一點方法總結(jié)
前兩天有一位網(wǎng)友提出了一個字符串內(nèi)截取字符串的問題,除了用普通的字符串截取的方式外,我推薦的是用LINQ方式來截取。兩者實際上差別不是很大,都是采用字符串截取方式,但后者從寫法和觀察效果會比前者簡單實用得多。2010-02-02Asp.Net Core實現(xiàn)Excel導(dǎo)出功能的實現(xiàn)方法
這篇文章主要給大家介紹了關(guān)于Asp.Net Core實現(xiàn)Excel導(dǎo)出功能的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12