日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

ASP.NET Core管道深度剖析[共4篇]

發(fā)布時間:2023/12/10 asp.net 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ASP.NET Core管道深度剖析[共4篇] 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

?

在《管道是如何處理HTTP請求的?》中,我們對ASP.NET Core的請求處理管道的構(gòu)成以及它對請求的處理流程進行了詳細介紹,接下來我們需要了解的是這樣一個管道是如何被構(gòu)建起來的。這樣一個管道由一個服務(wù)器和一個HttpApplication構(gòu)成,前者負責(zé)監(jiān)聽請求并將接收的請求傳遞給給HttpAppkication對象處理,后者則將請求處理任務(wù)委托給注冊的中間件來完成。中間件的注冊是通過ApplicationBuilder對象來完成的,所以我們先來了解一下這究竟是個怎樣的對象。

目錄
ApplicationBuilder
StartupLoader
WebHost
WeHostBuilder
總結(jié)

一、ApplicationBuilder

我們所說的ApplicationBuilder是對所有實現(xiàn)了IApplicationBuilder接口的所有類型及其對象的統(tǒng)稱。注冊到WebHostBuilder上的啟動類型具有一個用于管道定值的Configure方法,它利用作為參數(shù)的ApplicationBuilder對象進行中間件的注冊。由于ApplicationBuilder與組成管道的中間件具有直接的關(guān)系,所以我們得先來說說中間件在管道中究竟體現(xiàn)為一個怎樣的對象。

中間件在請求處理流程中體現(xiàn)為一個類型為Func<RequestDelegate,RequestDelegate>的委托對象,對于很多剛剛接觸請求處理管道的讀者朋友們來說,可能一開始對此有點難以理解,所以容來略作解釋。我們上面已經(jīng)提到過RequestDelegate這么一個委托,它相當(dāng)于一個Func<HttpContext, Task>對象,該委托對象表示針對提供的HttpContext所做進行一項處理操作,這項操作代表某個中間件針對請求的處理。那為何我們不直接用一個RequestDelegate對象來表示一個中間件,而將它表示成一個Func<RequestDelegate,RequestDelegate>對象呢?

在大部分應(yīng)用中,我們會針對具體的請求處理需求注冊多個不同的中間件,這些中間件按照注冊時間的先后順序進行排列進而構(gòu)成我們所謂的請求處理管道。對于某個中間件來說,在它完成了自身的請求處理任務(wù)之后,需要將請求傳遞給下一個中間件作后續(xù)的處理。Func<RequestDelegate,RequestDelegate>中作為輸入?yún)?shù)的RequestDelegate對象代表一個委托鏈,體現(xiàn)了后續(xù)中間件對請求的處理,當(dāng)前中間件將自身實現(xiàn)的請求處理任務(wù)添加到這個委托鏈中,而返回RequestDelegate對象代表最新的委托鏈。

以右圖所示的管道為例,如果用一個Func<RequestDelegate,RequestDelegate>來表示中間件B,那么作為輸入?yún)?shù)的RequestDelegate對象代表的是C對請求的處理操作,而返回值則代表B和C先后對請求處的處理操作。如果一個Func<RequestDelegate,RequestDelegate>代表第一個從服務(wù)器接收請求的中間件(比如A),那么執(zhí)行該委托對象返回的RequestDelegate實際上體現(xiàn)了整個管道對請求的處理。

在對中間件有了充分的了解之后,我們來看看用于注冊中間件的IApplicationBuilder接口的定義。如下所示的是經(jīng)過裁剪后的IApplicationBuilder接口的定義,我們只保留了兩個核心的方法,其中Use方法實現(xiàn)了針對中間件的注冊,另一個Build方法則將所有注冊的中間件轉(zhuǎn)換成一個RequestDelegate對象。

1: public interface IApplicationBuilder 2: { 3: RequestDelegate Build(); 4: IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware); 5: }

從編程便利性考慮,很多預(yù)定義的中間件都具有用于注冊的擴展方法,比如我們調(diào)用擴展方法UseStaticFiles來注冊處理靜態(tài)文件請求的中間件。對于我們演示的發(fā)布圖片的應(yīng)用來說,它也是通過調(diào)用一個具有如下定義的擴展方法UseImages來注冊處理圖片請求的中間件。

1: public static class ApplicationBuilderExtensions 2: { 3: public static IApplicationBuilder UseImages(this IApplicationBuilder app, string directory) 4: { 5: Func<RequestDelegate, RequestDelegate> middleware = next => 6: { 7: return context => 8: { 9: string fileName = context.Request.Url.LocalPath.TrimStart('/'); 10: if (string.IsNullOrEmpty(Path.GetExtension(fileName))) 11: { 12: fileName += ".jpg"; 13: } 14: fileName = Path.Combine(directory, fileName); 15: context.Response.WriteFile(fileName, "image/jpg"); 16: return next(context); 17: }; 18: }; 19: return app.Use(middleware); 20: } 21: }

ASP.NET Core默認使用的是一個類型為ApplicationBuilder的對象來注冊中間件,我們采用如下的代碼片斷來模擬它的實現(xiàn)邏輯。我們采用一個List<Func<RequestDelegate, RequestDelegate>>對象來存放所有注冊的中間件,并調(diào)用Aggregate方法將它轉(zhuǎn)換成一個RequestDelegate對象。

1: public class ApplicationBuilder : IApplicationBuilder 2: { 3: private IList<Func<RequestDelegate, RequestDelegate>> middlewares = new List<Func<RequestDelegate, RequestDelegate>>(); 4:? 5: public RequestDelegate Build() 6: { 7: RequestDelegate seed = context => Task.Run(() => {}); 8: return middlewares.Reverse().Aggregate(seed, (next, current) => current(next)); 9: } 10: 11: public IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware) 12: { 13: middlewares.Add(middleware); 14: return this; 15: } 16: }

ASP.NET Core并不會直接創(chuàng)建ApplicationBuilder對象來注冊中間件,而是利用對應(yīng)的工廠來創(chuàng)建它。創(chuàng)建愛你ApplicationBuilder的工廠通過接口IApplicationBuilderFactory表示,在模擬的管道中我們將這個接口簡化成如下的形式,該接口的默認實現(xiàn)者ApplicationBuilderFactory會直接創(chuàng)建一個ApplicationBuilder類型的對象。

1: public interface IApplicationBuilderFactory 2: { 3: IApplicationBuilder CreateBuilder(); 4: } 5:? 6: public class ApplicationBuilderFactory : IApplicationBuilderFactory 7: { 8: public IApplicationBuilder CreateBuilder() 9: { 10: return new ApplicationBuilder(); 11: } 12: }


二、StartupLoader

一個服務(wù)器和一組中間件組成了ASP .NET Core的HTTP請求處理管道,中間件的注冊通過調(diào)用ApplicationBuilder的Use方法來完成,而這一切實現(xiàn)在注冊為啟動類型的Configure方法中,我們可以將針對這個方法的調(diào)用抽象成一個類型為Action <IApplicationBuilder> 的委托對象。在管道初始化過程中,WebHost必須獲取并執(zhí)行這個委托以完成中間件的注冊工作。具體來說這個委托對象的獲取是利用一個名為StatupLoader對象來完成的。

這里的StartupLoader是對所有實現(xiàn)了IStartupLoader接口的所有類型機器對象的統(tǒng)稱,我們在模擬管道中將這個接口作了如下所示的簡化。IStartupLoader接口具有的唯一方法GetConfigureDelegate根據(jù)指定的啟動類型生成一個Action <IApplicationBuilder> 。對于默認實現(xiàn)該接口的StartupLoader類來說,它的GetConfigureDelegate方法返回的委托會以反射的方式執(zhí)行定義在指定啟動類型的Configure方法。簡單起見,我們假設(shè)這個Configure方法為實例方法,啟動對象可以直接調(diào)用默認無參構(gòu)造函數(shù)來創(chuàng)建。

1: public interface IStartupLoader 2: { 3: Action<IApplicationBuilder> GetConfigureDelegate(Type startupType); 4: } 5:? 6: public class StartupLoader : IStartupLoader 7: { 8: public Action<IApplicationBuilder> GetConfigureDelegate(Type startupType) 9: => app => startupType.GetMethod("Configure").Invoke(Activator.CreateInstance(startupType), new object[] { app }); 10: }


三、WebHost

ASP.NET Core的請求處理管道是由作為應(yīng)用宿主的WebHost對象創(chuàng)建出來的,后者是對所有實現(xiàn)了IWebHost接口的所有類型及其對象的統(tǒng)稱,我們在模擬管道中將這個接口作了如下的簡化,僅僅保留了唯一的方法Start。隨著WebHost因Start方法的調(diào)用而被開啟,整個管道也隨之被建立起來。

1: public interface IWebHost 2: { 3: void Start(); 4: }

通過上面的介紹我們知道請求處理管道可以理解為一個服務(wù)器和一個HttpApplication的組合,當(dāng)我們創(chuàng)建出一個服務(wù)器并指定一個具體的HttpApplication對象調(diào)用其Start方法將其啟動時,這個管道就被建立起來。服務(wù)器的創(chuàng)建是利用ServerFactory來完成的,而默認采用的HttpApplication類型為HostingApplication。

當(dāng)我們創(chuàng)建一個HostingApplication對象的時候,需要指定一個類型為RequestDelegate的委托對象,后者通過調(diào)用ApplicationBuilder的Build方法獲得,代表了所有注冊的中間件針對當(dāng)前請求的處理。所以HostingApplication的創(chuàng)建需要一個ApplicationBuilder對象,這個對象通過ApplicationBuilderFactory來創(chuàng)建。在調(diào)用ApplicationBuilder的Build方法將注冊的中間件轉(zhuǎn)換成RequestDelegate委托之前,需要完成針對中間件的注冊工作。實現(xiàn)在啟動類型的Configure方法中針對中間件的注冊可以體現(xiàn)為一個Action <IApplicationBuilder>對象,這對委托對象可以通過StartupLoader來獲取。

綜上所述,為了創(chuàng)建并啟動一個服務(wù)器,WebHost至少需要一個ServerFactory和ApplicationBuilderFactory來創(chuàng)建服務(wù)器和ApplicationBuilder,還需要一個StartupLoader來最終完成對中間件的注冊。除此之外,還需要知道注冊到WebHostBuilder上的啟動類型。由于依賴注入被廣泛應(yīng)用到了ASP.NET Core的請求處理管道中,對于前面三個對象,會先以服務(wù)的形式注冊到DI容器中,那么WebHost只需要利用ServiceProvider對象根據(jù)對應(yīng)的服務(wù)接口得到這三個對象。

1: public class WebHost : IWebHost 2: { 3: private IServiceProvider serviceProvider; 4: private Type startupType; 5:? 6: public WebHost(IServiceCollection appServices, Type startupType) 7: { 8: this.serviceProvider = appServices.BuildServiceProvider(); 9: this.startupType = startupType; 10: } 11:? 12: public void Start() 13: { 14: IApplicationBuilder applicationBuilder = serviceProvider.GetRequiredService<IApplicationBuilderFactory>().CreateBuilder(); 15: serviceProvider.GetRequiredService<IStartupLoader>().GetConfigureDelegate(startupType)(applicationBuilder); 16: IServer server = serviceProvider.GetRequiredService<IServerFactory>().CreateServer(); 17: server.Start(new HostingApplication(applicationBuilder.Build())); 18: } 19: }

由上面代碼片段提供的這個極簡版的WebHost類通過構(gòu)造函數(shù)的參數(shù)提供包含原始服務(wù)注冊的ServiceCollection對象和啟動類型,我們利用前者創(chuàng)建對應(yīng)的ServiceProvider。在Start方法中,我們利用ServiceProvider得到一個ApplicationBuilder對象和一個StartupLoader對象。我們將啟動類型作為參數(shù)調(diào)用StartupLoader的GetConfigureDelegate方法得到一個Action<IApplicationBuilder>對象。接下來,我們將ApplicationBuilder對象作為參數(shù)調(diào)用這個Action<IApplicationBuilder>委托對象,后者會執(zhí)行定義在啟動類型中的Configure方法并最終完整對中間件的注冊。

在這之后,我們利用ServiceProvider得到一個ServiceFactory對象并利用它創(chuàng)建出代碼服務(wù)器的Server對象。為了調(diào)用其Start方法,我們需要創(chuàng)建一個HostingApplication對象作為參數(shù),而后者的創(chuàng)建需要一個代表所有中間件針對當(dāng)前請求進行處理的RequestDelegate對象,這個對象直接通過調(diào)用ApplicationBuilder對象的Build方法得到。當(dāng)服務(wù)器因Start方法的調(diào)用而被啟動后,整個請求處理管道被正式建立起來。

四、WebHostBuilder

作為應(yīng)用宿主的WebHost創(chuàng)建了ASP.NET Core的請求處理管道,而WebHost又是由它的工廠WebHostBuilder創(chuàng)建的。WebHostBuilder是對所有實現(xiàn)了IWebHostBuilder接口的所有類型及其對象的統(tǒng)稱,我們在模擬管道中對這個接口做了極大的簡化,僅僅保留了如下面代碼片段所示的三個方法成員。針對WebHost的創(chuàng)建通過Build方法實現(xiàn),額外兩個方法(UseStartup和UseServer)分別用于注冊啟動類型和用于創(chuàng)建服務(wù)器的ServerFactory。

1: public interface IWebHostBuilder 2: { 3: IWebHostBuilder UseStartup(Type startupType); 4: IWebHostBuilder UseServer(IServerFactory factory); 5: IWebHost Build(); 6: }

依賴注入在ASP.NET Core 請求處理管道中得到了極大的應(yīng)用,創(chuàng)建WebHost提供的ServiceCollection對象最初由WebHostBuilder提供。WebHost在構(gòu)建管道時使用的一系列服務(wù)對象(ApplicationBuilderFactory和StartupLoader)最初都由WebHostBuilder注冊到這個ServiceCollection對象中,這一切都體現(xiàn)如下所示的這個默認使用的WebHostBuilder類型中。

1: public class WebHostBuilder : IWebHostBuilder 2: { 3: private Type startupType; 4: private IServiceCollection services; 5:? 6: public WebHostBuilder() 7: { 8: services = new ServiceCollection() 9: .AddTransient<IStartupLoader, StartupLoader>() 10: .AddTransient<IApplicationBuilderFactory, ApplicationBuilderFactory>(); 11: } 12:? 13: public IWebHost Build() => new WebHost(services, this.startupType); 14:? 15: public IWebHostBuilder UseServer(IServerFactory factory) 16: { 17: services.AddSingleton<IServerFactory>(factory); 18: return this; 19: } 20: 21: public IWebHostBuilder UseStartup(Type startupType) 22: { 23: this.startupType = startupType; 24: return this; 25: } 26: }


五、總結(jié)

綜上所述,我們已經(jīng)對ASP.NET Core應(yīng)用如何利用WebHostBuilder最終構(gòu)建出請求處理管道的流程以及管道自身處理請求的流程具有了一定的了解,現(xiàn)在我們來做一個簡單的總結(jié)。請求處理管道涉及到四個核心的對象,它們分別是WebHostBuilder、WebHost、Server和HttpApplication,它們之間具有如圖11所示的關(guān)系。我們通過WebHostBuilder來創(chuàng)建WebHost,并領(lǐng)用后者來構(gòu)建請求處理管道。

請求處理管道通過一個Server和一個HttpApplication對象組成,后者是對所有注冊的中間件的封裝。當(dāng)WebHost被啟動的時候,它會創(chuàng)建Server和HttpApplication對象,并將后者作為參數(shù)調(diào)用Server的Start方法以啟動服務(wù)器。啟動后的Server開啟監(jiān)聽請求并利用HttpApplication來處理接收到請求。當(dāng)HttpApplication完成了所有請求處理工作之后,它會利用Server完成對請求的最終響應(yīng)。

上面所述的所有內(nèi)容都是針對我們自定義的模擬管道來介紹的,雖然我們對這個模擬管道做了極大的簡化,但是它依然體現(xiàn)了ASP.NET Core管道處理請求的真實流程,而且真實管道的創(chuàng)建方式也與模擬管道基本一致。如果讀者朋友們能夠?qū)@個模擬管道具有深刻的理解,我相信對真實管道的把握就會變得非常容易。

?

?


一、采用管道處理HTTP請求
二、創(chuàng)建一個“迷你版”的管道來模擬真實管道請求處理流程?
三、管道如何處理HTTP請求的
四、管道是如何被創(chuàng)建出來的

?

總結(jié)

以上是生活随笔為你收集整理的ASP.NET Core管道深度剖析[共4篇]的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。