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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

学习ASP.NET Core,你必须了解无处不在的“依赖注入”

發布時間:2023/12/4 asp.net 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 学习ASP.NET Core,你必须了解无处不在的“依赖注入” 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

ASP.NET Core的核心是通過一個Server和若干注冊的Middleware構成的管道,不論是管道自身的構建,還是Server和Middleware自身的實現,以及構建在這個管道的應用,都需要相應的服務提供支持,ASP.NET Core自身提供了一個DI容器來實現針對服務的注冊和消費。換句話說,不只是ASP.NET Core底層框架使用的服務是由這個DI容器來注冊和提供,應用級別的服務的注冊和提供也需要以來這個DI容器,所以正如本文標題所說的——學習ASP.NET Core,你必須了解無處不在的“依賴注入”。


目錄一、依賴注入簡介

二、依賴注入在管道構建過程中的應用

三、依賴服務的注冊與注入

四、讓Startup的ConfigureServices方法返回一個ServiceProvider

五、ASP.NET Core默認注冊了哪些服務

六、ASP.NET Core MVC中的依賴注入


一、依賴注入簡介


說到依賴注入(Dependency Injection,以下簡稱DI),就必須說IoC(Inverse of Control),很多人將這兩這混為一談,其實這是兩個完全不同的概念,或者是不同“層次”的兩個概念,我曾在《控制反轉(IoC)》和《依賴注入(DI)》對這兩個概念做過詳細介紹。ASP.NET Core使用的DI框架由“Micorosoft.Extensions.DependencyInjection”這個NuGet包來承載,我們也可以非ASP.NET Core應用或者你自己的框架上單獨使用它,對于這個DI框架的設計、實現以及編程相關的內容,我在系列文章《ASP.NET Core 中的依賴注入 [共7篇]》對此有過詳細的介紹。


DI框架具有兩個核心的功能,即服務的注冊和提供,這兩個功能分別由對應的對象來承載, 它們分別是ServiceCollectionServiceProvider。如下圖所示,我們將相應的服務以不同的生命周期模式(Transient、Scoped和Singleton)注冊到ServiceCollection對象之上,在利用后者創建的ServiceProvider根據注冊的服務類型提取相應的服務對象。



二、依賴注入在管道構建過程中的使用


在ASP.NET Core管道的構架過程中主要涉及三個對象/類型,作為宿主的WebHost和他的創建者WebHostBuilder,以及注冊到WebHostBuilder的Startup類型。 如下的代碼片段體現了啟動ASP.NET Core應用采用的典型編程模式:我們首先創建一個WebHostBuilder對象,并將采用Server和Startup類型注冊到它之上。在調用Build方法創建WebHost之前,我們還可以調用相應的方式做其他所需的注冊工作。當我們調用WebHost的Run方法之后,后者會利用注冊的Startup類型來構建完整的管道。那么在管道的構建過程中,DI是如何被應用的呢?


? ?1: new WebHostBuilder()

? ?2: ? ? .UseKestrel()

? ?3: ? ? .UseStartup<Startup>()

? ?4: ? ? .Xxx

? ?5: ? ? .Build()

? ?6: ? ? .Run()


DI在管道ASP.NET Core管道構建過程中的應用基本體現下面這個序列圖中。當我們調用WebHostBuilder的Build方法創建對應的WebHost的時候,前者會創建一個ServiceCollection對象,并將一系列預定義的服務注冊在它之上。接下來WebHostBuilder會利用這個ServiceCollection對象創建出對應的ServieProvider,這個ServiceProvider和ServiceCollection對象會一并傳遞給最終創建WebHost對象。當我們調用WebHost的Run方法啟動它的時候,如果注冊的Startup是一個實例類型,它會利用這個ServiceProvider以構造器注入的方式創建對應的Startup對象。說的具體一點,我們注冊的Startup類型的構造函數是允許定義參數的,但是參數類型必須是預先注冊到ServiceCollection中的服務類型。



注冊的Startup方法可以包含一個可選的ConfigureServices方法,這個方法具有一個類型為IServiceCollection接口的參數。WebHost會將WebHostBuilder傳遞給它的ServiceCollection作為參數調用這個ConfigureServices方法,而我們則利用這個方法將注冊的中間件和應用所需的服務注冊到這個ServiceCollection對象上。在這之后,所有需要的服務(包括框架和應用注冊的服務)都注冊到這個ServiceCollection上面,WebHost會利用它創建一個新的ServiceProvider。WebHost會利用這個ServiceProvider對象以方法注入的方式調用Startup對象/類型的Configure方法,最終完成你對整個管道的建立。換句話會說,定義在Startup類型中旨在用于注冊Middleware的Configure方法除了采用IApplicationBuilder作為第一個參數之外,它依然可以采用注冊的任何一個服務類型作為后續參數的類型。


服務的注冊除了是現在注冊的Startup類型的ConfigureServices方法之外,實際上還具有另一個實現方式,那就是調用WebHostBuilder具有如下定義的ConfigureServices方法。當WebHostBuilder創建出ServiceCollection對象并完成了默認服務的注冊后,我們通過調用這個方法所傳入的所有Action<IServiceCollection>對象將最終應用到這個ServiceCollection對象上。


? ?1: public interface IWebHostBuilder

? ?2: {

? ?3: ? ? IWebHostBuilder ConfigureServiecs(Action<IServiceCollection> configureServices);

? ?4: }


值得一提的是,Startup類型的ConfigureServices方法是允許具有一個IServiceProvider類型的返回值,如果這個方法返回一個具體的ServiceProrivder,那么WebHost將不會利用ServiceCollection來創建ServiceProvider,而是直接使用這個返回的ServiceProvider來調用Startup對象/類型的Configure方法。這實際上是一個很有用的擴展點,我們使用它可以實現針對其它DI框架的集成。


三、依賴服務的注冊與注入


接下來我們通過一個實例來演示如何利用Startup類型的ConfigureServices來注冊服務,以及發生在Startup類型上的兩種依賴注入形式。如下面的代碼片段所示,我們定義了兩個服務接口(IFoo和IBar)和對應的實現類型(Foo和Bar)。其中其中服務Foo是通過調用WebHostBuilder的ConfigureServices方法進行注冊的,而另一個服務Bar的注冊則發生在Startup的ConfigureServices方法上。對于Startup來說,它具有一個類型為IFoo的只讀屬性,該屬性在構造函數利用傳入的參數進行初始化,不用是這體現了針對Startup的構造器注入。Startup的Configure方法除了ApplicationBuilder作為第一個參數之外,還具有另一個類型為IBar的參數,我們利用它來演示方法注入。


? ?1: public interface IFoo { }

? ?2: public interface IBar { }

? ?3: public class Foo : IFoo { }

? ?4: public class Bar : IBar { }

? ?5: ?

? ?6: public class Program

? ?7: {

? ?8: ? ? public static void Main(string[] args)

? ?9: ? ? {

? 10: ? ? ? ? new WebHostBuilder()

? 11: ? ? ? ? ? ? .ConfigureServices(services=>services.AddSingleton<IFoo, Foo>())

? 12: ? ? ? ? ? ? .UseKestrel()

? 13: ? ? ? ? ? ? .UseStartup<Startup>()

? 14: ? ? ? ? ? ? .Build()

? 15: ? ? ? ? ? ? .Run();

? 16: ? ? }

? 17: }

? 18: public class Startup

? 19: {

? 20: ? ? public IFoo Foo { get; private set; }

? 21: ? ? public Startup(IFoo foo)

? 22: ? ? {

? 23: ? ? ? ? this.Foo = foo;

? 24: ? ? } ? ?

? 25: ? ? public void ConfigureServices(IServiceCollection services)

? 26: ? ? {

? 27: ? ? ? ? services.AddTransient<IBar, Bar>();

? 28: ? ? }

? 29: ? ??

? 30: ? ? public void Configure(IApplicationBuilder app, IBar bar)

? 31: ? ? {

? 32: ? ? ? ? app.Run(async context =>

? 33: ? ? ? ? {

? 34: ? ? ? ? ? ? context.Response.ContentType = "text/html";

? 35: ? ? ? ? ? ? await context.Response.WriteAsync($"IFoo=>{this.Foo}<br/>");

? 36: ? ? ? ? ? ? await context.Response.WriteAsync($"IBar=>{bar}");

? 37: ? ? ? ? });

? 38: ? ? }

? 39: }


在Startup的Configure方法中,我們調用ApplicationBulder的Run方法注冊了一個Middleware,后者將兩個注入的服務的類型作為響應的內容。當我們運行這個應用,并利用瀏覽器訪問默認的監聽地址(http://localhost:5000)時,瀏覽器會將注入的兩個服務對象的類型以下圖的方式展現出來。


四、讓Startup的ConfigureServices方法返回一個ServiceProvider


我們說注冊的Startup類型的ConfigureServices允許返回一個ServiceProvider,這個特性的重要意義在于它使我們可以實現與第三方DI框架(比如Unity、Castle、Ninject和AutoFac等)的集成。我們照例采用一個實例對此做一個演示,簡單起見,我們并不會真正利用某個具體的DI框架來創建這個ServiceProvider,而是直接創建一個新的ServiceCollection來創建它,為此我們對上面這個程序進行了如下的改寫。


? ?1: public class Program

? ?2: {

? ?3: ? ? public static void Main(string[] args)

? ?4: ? ? {

? ?5: ? ? ? ? new WebHostBuilder()

? ?6: ? ? ? ? ? ? .UseKestrel()

? ?7: ? ? ? ? ? ? .UseStartup<Startup>()

? ?8: ? ? ? ? ? ? .Build()

? ?9: ? ? ? ? ? ? .Run();

? 10: ? ? }

? 11: }

? 12: public class Startup

? 13: { ??

? 14: ? ? public IServiceProvider ConfigureServices(IServiceCollection services)

? 15: ? ? {

? 16: ? ? ? ? IServiceCollection newServices = new ServiceCollection();

? 17: ? ? ? ? foreach (ServiceDescriptor service in services)

? 18: ? ? ? ? {

? 19: ? ? ? ? ? ? newServices.Add(service);

? 20: ? ? ? ? }

? 21: ?

? 22: ? ? ? ? return newServices

? 23: ? ? ? ? ? ? .AddSingleton<IFoo, Foo>()

? 24: ? ? ? ? ? ? .AddSingleton<IBar, Bar>()

? 25: ? ? ? ? ? ? .BuildServiceProvider();

? 26: ? ? }

? 27: ? ??

? 28: ? ? public void Configure(IApplicationBuilder app, IFoo foo, IBar bar)

? 29: ? ? {

? 30: ? ? ? ? app.Run(async context =>

? 31: ? ? ? ? {

? 32: ? ? ? ? ? ? context.Response.ContentType = "text/html";

? 33: ? ? ? ? ? ? await context.Response.WriteAsync($"IFoo=>{foo}<br/>");

? 34: ? ? ? ? ? ? await context.Response.WriteAsync($"IBar=>{bar}");

? 35: ? ? ? ? });

? 36: ? ? }

? 37: }


如上面的代碼片段所示,在Startup的ConfigureServices方法中,我們通過拷貝注冊到現有ServiceCollection的所有ServiceDescriptor生成了一個新的ServiceCollection,兩個服務Foo和Bar被注冊到后者之上。該方法最終返回由這個新ServiceCollection創建的ServiceProvider。在另一個Configure方法中,我們添加了兩個類型分別為IFoo和IBar的參數,并以相同的方式將它們的真實類型名稱和注冊服務類型的映射關系作為響應內容。程序運行之后,我們利用瀏覽器進行訪問照樣會得到一樣的結果。


五、ASP.NET Core默認注冊了哪些服務


WebHostBuilder在創建ServiceCollection之后,會注冊一些默認的服務。這些服務和我們自行注冊的服務并沒有任何區別,只要我們知道對應的服務類型,就可以通過注入的方式獲取并使用它們。那么具體由哪些服務被默認注冊了呢?如下所示的是這些服務對應的類型,至于這些服務各自有何用途,我們在這里就先不深究了。

  • IHostingEnvironment

  • ILoggerFactory

  • ILogger<>

  • IApplicationBuilderFactory

  • IHttpContextFactory

  • IOptions<>

  • DiagnosticSource

  • DiagnosticListener

  • IStartupFilter

  • ObjectPoolProvider

  • IStartup

如果我們需要這些預注冊的服務,我們可以按照我們熟悉的方式以依賴注入的方式來使用它們。如下面的代碼片段所示,我們在Startup的Configure方法中直接采用方法注入的方式來使用這些預定義的服務。


? ?1: public class Program

? ?2: {

? ?3: ? ? public static void Main(string[] args)

? ?4: ? ? {

? ?5: ? ? ? ? new WebHostBuilder()

? ?6: ? ? ? ? ? ? .UseKestrel()

? ?7: ? ? ? ? ? ? .UseStartup<Startup>()

? ?8: ? ? ? ? ? ? .Build()

? ?9: ? ? ? ? ? ? .Run();

? 10: ? ? }

? 11: }

? 12: public class Startup

? 13: { ? ??

? 14: ? ? public void Configure(

? 15: ? ? ? ? IApplicationBuilder app,

? 16: ? ? ? ? IHostingEnvironment environment,

? 17: ? ? ? ? ILoggerFactory loggerFactory,

? 18: ? ? ? ? IHttpContextFactory httpContextFactory,

? 19: ? ? ? ? DiagnosticSource diagnosticSource,

? 20: ? ? ? ? DiagnosticListener diagnosticListener)

? 21: ? ? {

? 22: ? ? ? ? app.Run(async context =>

? 23: ? ? ? ? {

? 24: ? ? ? ? ? ? context.Response.ContentType = "text/html";

? 25: ? ? ? ? ? ? await context.Response.WriteAsync($"IApplicationBuilder=>{app}<br/>");

? 26: ? ? ? ? ? ? await context.Response.WriteAsync($"IHostingEnvironment=>{environment}<br/>");

? 27: ? ? ? ? ? ? await context.Response.WriteAsync($"ILoggerFactory=>{loggerFactory}<br/>");

? 28: ? ? ? ? ? ? await context.Response.WriteAsync($"IHttpContextFactory=>{httpContextFactory}<br/>");

? 29: ? ? ? ? ? ? await context.Response.WriteAsync($"DiagnosticSource=>{diagnosticSource}<br/>");

? 30: ? ? ? ? ? ? await context.Response.WriteAsync($"DiagnosticListener=>{diagnosticListener}");

? 31: ? ? ? ? });

? 32: ? ? }

? 33: }


由于Configure方法注冊的Middleware直接將注入服務的注冊類型和真實類型的映射關系作為響應內容,所以我們訪問應用會的得到如下所示的輸出結果。



六、ASP.NET Core MVC中的依賴注入


對于ASP.NET MVC 5機器以及之前的版本,在默認情況下定義的Controller都具有一個要求,那就是Controller類型必須具有一個無參數的默認構造函數,否則Controller實例將無法激活。對于自身具有依賴注入功能的ASP.NET Core MVC來說,定義Controller將沒有了這個限制。對于預注冊的服務,我們完全可以采用構造器注入的方式在定義的Controller中使用它們。作為演示,我們對上面這個應用作了如下的改寫。


? ?1: public class Program

? ?2: {

? ?3: ? ? public static void Main(string[] args)

? ?4: ? ? {

? ?5: ? ? ? ? new WebHostBuilder()

? ?6: ? ? ? ? ? ? .UseKestrel()

? ?7: ? ? ? ? ? ? .ConfigureServices(services=>services

? ?8: ? ? ? ? ? ? ? ? .AddSingleton<IFoo,Foo>()

? ?9: ? ? ? ? ? ? ? ? .AddSingleton<IBar,Bar>()

? 10: ? ? ? ? ? ? ? ? .AddMvc())

? 11: ? ? ? ? ? ? .Configure(app=>app.UseMvc())

? 12: ? ? ? ? ? ? .Build()

? 13: ? ? ? ? ? ? .Run();

? 14: ? ? }

? 15: }

? 16: ?

? 17: public class HomeController

? 18: {

? 19: ? ? public IFoo Foo { get; private set; }

? 20: ? ? public IBar Bar { get; private set; }

? 21: ?

? 22: ? ? public HomeController(IFoo foo, IBar bar)

? 23: ? ? {

? 24: ? ? ? ? this.Foo = foo;

? 25: ? ? ? ? this.Bar = bar;

? 26: ? ? }

? 27: ?

? 28: ? ? [HttpGet("/")]

? 29: ? ? public string Index()

? 30: ? ? {

? 31: ? ? ? ? this.HttpContext.Response.ContentType = "text/html";

? 32: ? ? ? ? return $"IFoo=>{this.Foo}<br/>IBar=>{this.Bar}";

? 33: ? ? } ? ? ??

? 34: }


上面這個代碼與之前有一個顯著的區別,那就是我們根本就沒有定義Startup類型,我們將原本實現在它的兩個方法(ConfigureServices和Configure)中的功能移植到了WebHostBuilder的同名方法中,這兩種形式的編程方式其實是等效的。在調用ConfigureServices方法的時候,我們除了注冊MVC相關的服務之外,Foo和Bar這兩個服務也一并進行了注冊。至于另一個Configure方法,我們直接調用其擴展方法MVC注冊與MVC相關的Middleware。


我們定義了一個默認的HomeController,它具有兩個類型分別為IFoo和IBar的只讀屬性,后者在構造函數由傳入的參數進行初始化,我們知道這是構造器注入的編程方式。在Action方法Index中 ,我們依然將這兩個服務的注冊類型和真實類型之間的匹配關系作為響應內容,所以我們訪問這個應用依然會得到如下所示的輸出結果。




請掃描此二維碼或者搜索“大內老A”關注蔣金楠(Artech)微信公眾帳號,你將會得到及時的高質量技術文章推送信息。

內容轉載自公眾號

大內老A 了解更多 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的学习ASP.NET Core,你必须了解无处不在的“依赖注入”的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: a猛片 | 性色视频在线 | 一区二区在线免费 | 我要操婊| 五月婷婷六月香 | 五十路黄色片 | 免费又黄又爽又色的视频 | 黄色片在线免费观看视频 | 青娱乐国产在线 | 貂蝉被到爽流白浆在线观看 | www.youjizz.com日本 | 我的公把我弄高潮了视频 | 麻豆久久精品 | 亚洲精品喷潮一区二区三区 | 久久99精品国产.久久久久 | 国产性猛交96| 中文字幕xxx| 一本一道波多野结衣av黑人 | 亚洲24p | 国产丝袜在线 | 国产免费黄色片 | 久久综合桃花网 | 亚洲性影院 | 免费一级淫片aaa片毛片a级 | 日本午夜啪啪 | 亚洲激情av| 波多野结衣加勒比 | 日韩中文字幕高清 | 中文字幕第6页 | 日韩精品久久久久久久电影99爱 | 日韩精品中文字幕在线 | 日本中文视频 | 精品乱人伦一区二区三区 | 可以在线观看av的网站 | 午夜在线观看一区 | 国产一区二区精品在线 | 国产69精品久久久久999小说 | www.av网| 三级网站免费观看 | 深夜国产福利 | 欧美一区二区三区婷婷月色 | www.激情网 | 日韩在线观看免费av | 第一章激情艳妇 | 精品久久久蜜桃 | 精品无码人妻少妇久久久久久 | 亚洲视频免费观看 | 色咪咪网站| 亚洲无在线观看 | a级在线看 | 欧美有码在线观看 | 麻豆精品在线观看 | 亚洲成人精品一区二区三区 | 亚洲综合五月天婷婷丁香 | 午夜免费激情视频 | 亚洲女则毛耸耸bbw 边吃奶边添下面好爽 | 免费看女人裸体 | 亚洲另类色图 | 在线高清免费观看 | 尤物一区 | 99久久99久久精品免费看蜜桃 | 国产精品1000部啪视频 | 97人人模人人爽人人少妇 | 国产精品国产三级国产普通话对白 | 日韩激情精品 | 色婷婷电影网 | 午夜寂寞自拍 | 国内精品久久久久久久久久久 | 天天干夜夜夜 | 中文区中文字幕免费看 | 国产乱来 | 久久精品色欲国产AV一区二区 | 四虎精品一区二区 | 欧美日韩国产三级 | 日韩a∨| 精品一区二区视频 | 亲子乱一区二区三区 | 久久久久久不卡 | 久草资源在线 | 精品国偷自产国产一区 | 日本h在线观看 | 秋霞av鲁丝片一区二区 | 精品香蕉视频 | 日韩国产精品一区 | 91精品视频网站 | 俺来也av| 国产色视频在线 | 日韩精品一区二区免费视频 | 五月天堂婷婷 | 蜜臀aⅴ国产精品久久久国产老师 | 日韩精品国产一区二区 | 伊人久久大香线蕉综合网站 | 中文字幕乱码亚洲无线三区 | 国产一级久久 | 四季av一区二区三区免费观看 | 精品美女久久 | 国产女教师一区二区三区 | 直接看毛片 | 少妇av|