ASP.NET Core Middleware
中間件(Middleware)是ASP.NET Core中的一個重要特性。所謂中間件就是嵌入到應用管道中用于處理請求和響應的一段代碼。ASP.NET Core Middleware可以分為兩種類型:
Conventional Middleware
IMiddleware
Conventional Middleware
這種中間件沒有實現特定的接口或者繼承特定類,它更像是Duck Typing (你走起路來像個鴨子, 叫起來像個鴨子, 那么你就是個鴨子)。有兩種表現形式:
匿名方法
這種方式又稱為內聯中間件(in-line middleware),可以使用Run,?Map,?Use,MapWhen等擴展方法來實現。如:
IApplicationBuilder的擴展方法:Run、Map、MapWhen及
Use(this IApplicationBuilder app, Func<HttpContext, Func<Task>, Task> middleware),最終都會調用IApplicationBuilder接口中的Use(Func<RequestDelegate, RequestDelegate> middleware)方法來實現向請求處理管道中注入中間件,后面會對源碼做分析。
自定義中間件類
這種形式利于代碼的復用,如:
將自定義中間件配置到請求處理管道中
public void Configure(IApplicationBuilder app, IHostingEnvironment env) {app.UseXfhMiddleware(); }IMiddleware
IMiddleware提供了強類型約束的中間件,其默認實現是MiddlewareFactory,接口定義如下:
public interface IMiddleware {Task InvokeAsync(HttpContext context, RequestDelegate next); }IMiddlewareFactory用于創建IMiddleware實例及對實例進行回收,接口定義:
將中間件注入到請求處理管道:
public void Configure(IApplicationBuilder app, IHostingEnvironment env) {app.UseMyMiddleware(); }?
使用IMiddleware類型的中間件需要在容器中進行注冊,否則拋異常,具體原因下面分析:
?
?將中間件注入到容器中:
一段警告
下面貼一段微軟文檔中的警告,大意是不要試圖去改變已發往客戶端的響應內容,否則可能會引發異常。實在是太懶了,不想翻譯就把原文貼出來了:
Warning
Don't call?next.Invoke?after the response has been sent to the client. Changes to?HttpResponse?after the response has started throw an exception. For example, changes such as setting headers and a status code throw an exception. Writing to the response body after calling next:
May cause a protocol violation. For example, writing more than the stated Content-Length.
May corrupt the body format. For example, writing an HTML footer to a CSS file.
HasStarted?is a useful hint to indicate if headers have been sent or the body has been written to.
UseMiddleware
前面將自定義中間件注入到請求處理管道時用到了UseMiddleware方法,從方法簽名中可以看到UserMiddleware可以接受多個參數:
接下來我們看下UserMiddleware方法的具體實現,由于該方法代碼量較大,所以這里只看其中的關鍵部分,方法整體流程如下:
該方法首先判斷傳入的middleware是否是IMiddleware類型,如果是則調用UseMiddlewareInterface
從這段代碼中可以看到IMiddlewareFactory負責創建并回收IMiddleware對象
從MiddlewareFactory的Create方法中可以看到,IMiddleware實例是從容器中獲取的,若容器中找不到則會拋出異常:
若是Conventional Middleware則判斷傳入的middleware是否符合約束
首先判斷傳入的middleware中是否僅包含一個名稱為Invoke或InvokeAsync的公共實例方法
其次判斷方法的返回類型是否是Task:
然后再判斷,方法的第一個參數是否是HttpContext類型:
對于Invoke或InvokeAsync僅包含一個HttpContext類型參數的情況用到了反射(ActivatorUtilities.CreateInstance方法中)來構建RequestDelegate
對于包含多個參數的情況,則使用了表達式樹來構建RequestDelegate
完整的代碼可以在Github上看到。
Use(Func<RequestDelegate, RequestDelegate> middleware)
上述所有中間件,最終都會調用IApplicationBuilder接口中的Use(Func<RequestDelegate, RequestDelegate> middleware)方法來實現向請求處理管道中注冊中間件,該方法在ApplicationBuilder類的實現如下:
從上面代碼中可以看到,中間件是一個RequestDelegate類型的委托,請求處理管道其實是一個委托列表,請求委托簽名如下:
public delegate Task RequestDelegate(HttpContext context);?
與ASP.NET處理管道的區別
?
?
?
傳統的ASP.NET的處理管道是基于事件模型的,處理管道有多個IHttpModule和一個IHttpHandler組成。請求處理管道中各個模塊被調用的順序取決于兩方面:
模塊所注冊事件被觸發的先后順序
注冊同一事件的不同模塊執行先后順序有Web.config中的配置順序決定
?
?
?
ASP.NET Core的請求處理管道則是有一堆中間件組成,相對ASP.NET更簡單。
中間件處理請求和響應的順序只與其在代碼中的注冊順序有關:處理請求按注冊順序依次執行,處理響應按注冊順序反方向依次執行。
其次,在ASP.NET Core中只需使用代碼,而無需使用Global.asax和Web.config來配置請求處理管道。
小結
所謂中間件就是嵌入到應用管道中用于處理請求和響應的一段代碼,它主要有兩個作用:
處理請求和響應
可以阻止請求發往請求處理管道中的下一個中間件
在ASP.NET Core中,中間件是以RequestDelegate委托的形式體現的。
ASP.NET Core中整個請求處理管道的創建是圍繞這種IApplicationBuilder接口進行的,請求處理管道是一個List<RequestDelegate>類型的列表。
推薦閱讀
ASP.NET Core Middleware
Factory-based middleware activation in ASP.NET Core
Migrate HTTP handlers and modules to ASP.NET Core middleware
ASP.NET MVC5請求處理管道和生命周期
用ASP.NET Core 2.0 建立規范的 REST API -- 預備知識
原文地址:https://www.cnblogs.com/Cwj-XFH/p/9690728.html
.NET社區新聞,深度好文,歡迎訪問公眾號文章匯總 http://www.csharpkit.com
總結
以上是生活随笔為你收集整理的ASP.NET Core Middleware的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: .NET Core 出得云端入得本地,微
- 下一篇: ASP.NET Core 中的依赖注入