1. 程式人生 > >ASP.NET Core中如影隨形的”依賴注入”[下]: 歷數依賴注入的N種玩法

ASP.NET Core中如影隨形的”依賴注入”[下]: 歷數依賴注入的N種玩法

在對ASP.NET Core管道中關於依賴注入的兩個核心物件(ServiceCollection和ServiceProvider)有了足夠的認識之後,我們將關注的目光轉移到程式設計層面。在ASP.NET Core應用中基於依賴注入的程式設計主要涉及到兩個方面,它們分別是將服務註冊到ServiceCollection中,和採用注入的方式利用ServiceProvider提供我們所需的服務。我們先來討論ASP.NET Core應用中如何進行服務註冊。[本文已經同步到《ASP.NET Core框架揭祕》之中]

目錄
一、服務註冊
    系統自動註冊的服務
    手工註冊的服務
二、以注入的形式提取服務
    啟動型別的建構函式和Configure方法種注入服務
    中介軟體型別的建構函式和Invoke方法中注入服務
    Controller型別的建構函式中注入服務
    View中注入服務
三、與第三方DI框架的整合

一、服務註冊

就註冊的主體來劃分,ASP.NET Core應用中註冊的服務大體可以分為兩種型別,一種是WebHostBuilder在建立WebHost之前自動註冊的服務,這些服務確保了後續管道能夠順利構建並能提供基本的請求處理能力。另一種則是使用者根據自身的需要註冊的,如果系統自動註冊的服務不符合我們的需求,我們也可以註冊自己的服務來覆蓋它。

系統自動註冊的服務

那麼系統在構建ASP.NET Core管道的時候到底自行註冊了那些服務呢?對於這個問題,我們不用去檢視相關的原始碼如何編寫,而只需要編寫如下一個簡單的程式就可以將這些服務輸出來。

   1: public class Program
   2: {
   3:     public static void Main()
   4:     {
   5:         Console.WriteLine("{0,-30}{1,-15}{2}", "Service Type", "Lifetime", "Implementation");
   6:         Console.WriteLine("-------------------------------------------------------------");
   7:  
   8:         new WebHostBuilder()
   9:             .UseKestrel()
  10:             .Configure(app => { })
  11:             .ConfigureServices(svcs =>
  12:             {
  13:                 IServiceProvider serviceProvider = svcs.BuildServiceProvider();
  14:                 foreach (var svc in svcs)
  15:                 {
  16:                     if (null != svc.ImplementationType)
  17:                     {
  18:                         Console.WriteLine("{0,-30}{1,-15}{2}", svc.ServiceType.Name, svc.Lifetime, svc.ImplementationType.Name);
  19:                         continue;
  20:                     }
  21:                     object instance = serviceProvider.GetService(svc.ServiceType);
  22:                     Console.WriteLine("{0,-30}{1,-15}{2}", svc.ServiceType.Name, svc.Lifetime, instance.GetType().Name);
  23:                 }
  24:  
  25:             })
  26:             .Build();
  27:     }
  28: }

如上面的程式碼片斷所示,我們利用WebHostBuilder建立了一個WebHost物件。在此之前,我們呼叫擴充套件方法UseKestrel註冊了一個KestrelServer型別的伺服器,指定一個空的Action<IApplicationBuilder>物件作為引數呼叫了它的Configure方法,我們只得到這樣的方法呼叫會建立了一個DelegateStartup物件。我們直接利用ConfigureServices方法得到所有自動註冊的服務,並打印出每個服務的註冊型別、生命週期模式和實現型別。當我們執行這個程式之後,控制檯上將打印出如下圖所示的服務列表。對於列出的這些服務,我們是不是看到很多熟悉的身影?

4

手工註冊的服務

如果具體的專案需要採用依賴注入的方式來完成一些業務功能的實現,那就需要在應用初始化的過程中手工註冊相應的服務。初次之外,我們也可以採用手工註冊服務的方式來覆蓋系統自動註冊的服務。總的來說,我們可以採用種方式實現對服務的手工註冊,其中一種就是按照如下的形式呼叫WebHostBuilder的ConfigureServices方法來註冊服務,而另一種則是將服務註冊實現在啟動類的ConfigureServices方法中。

註冊方式1:

   1: new WebHostBuilder()
   2:     .ConfigureServices(svcs => svcs
   3:         .AddTransient<IFoo, Foo>()
   4:         .AddScoped<IBar, IBar>()
   5:         .AddSingleton<IBaz, Baz>())
   6:     …

註冊方式2:

   1: public class Startup
   2: {   
   3:     public void ConfigureServices(IServiceCollection svcs)
   4:     {
   5:         svcs.AddTransient<IFoo, Foo>()
   6:             .AddScoped<IBar, IBar>()
   7:             .AddSingleton<IBaz, Baz>();
   8:     }
   9:     …
  10: }

通過前面的介紹,我們知道這兩種方式真正執行服務註冊的時機是不同的。第一種形式的服務註冊發生在WebHostBuilder建立WebHost之前,包含這些服務的ServiceCollection以及由此建立的ServiceProvider將直接提供給後續建立的WebHost。而第二種形式的服務註冊則發生在WebHost初始化過程中,實際上是藉助一個ConventionBasedStartup物件來完成的。

二、以注入的形式提取服務

依賴注入的最終目錄在於實現以注入的形式來消費預先註冊的服務。在一個ASP.NET Core應用中,我們在很多地方都可以採用這種程式設計方式,我們在前一章中對此也有所提及。經過我的總結,我們常用的依賴注入程式設計主要應用在如下幾個方面:

  • 啟動型別的建構函式和Configure方法中定義相應引數以注入的形式獲取註冊的服務。
  • 中介軟體型別的建構函式和Invoke方法定義任何引數以注入的形式獲取註冊的服務。
  • ASP.NET Core MVC應用中Controller型別的建構函式中定義任何引數以注入的形式獲取註冊的服務。
  • ASP.NET Core MVC應用的View中通過@inject指令直接獲取註冊的服務。

啟動型別的建構函式和Configure方法種注入服務

當我們在定義啟動型別的時候,通過呼叫WebHostBuilder的ConfigureServices方法註冊的服務可以在啟動類的建構函式中進行注入,而啟動類的Configure方法不但可以注入呼叫WebHostBuilder的ConfigureServices方法註冊的服務,也可以注入自身ConfigureServices方法註冊的服務。如下所示的程式碼片斷展示了一個比較典型的例子。

   1: new WebHostBuilder()
   2:     .UseKestrel()
   3:     .ConfigureServices(svcs => svcs
   4:         .AddSingleton<IFoo, Foo>()
   5:         .AddSingleton<IBar, Bar>())
   6:     .UseStartup<Startup>()
   7:     …
   8:  
   9: public class Startup
  10: {
  11:     public Startup(IFoo foo, IBar bar)
  12:     {
  13:         Debug.Assert(typeof(Foo).IsInstanceOfType(foo));
  14:         Debug.Assert(typeof(Bar).IsInstanceOfType(bar));
  15:     }
  16:  
  17:     public void ConfigureServices(IServiceCollection svcs)
  18:     {
  19:         svcs.AddTransient<IBaz, Baz>()
  20:             .AddTransient<IGux, Gux>();
  21:     }
  22:  
  23:     public void Configure(IApplicationBuilder app, IFoo foo, IBar bar, IBaz baz, IGux gux)
  24:     {
  25:         Debug.Assert(typeof(Foo).IsInstanceOfType(foo));
  26:         Debug.Assert(typeof(Bar).IsInstanceOfType(bar));
  27:         Debug.Assert(typeof(Baz).IsInstanceOfType(baz));
  28:         Debug.Assert(typeof(Gux).IsInstanceOfType(gux));
  29:     }        
  30: }

中介軟體型別的建構函式和Invoke方法中注入服務

當我們按照約定定義中介軟體型別的時候,我們可以在建構函式定義相應的引數來注入通過任何形式註冊的服務。如下面的程式碼片斷所示,中介軟體型別的建構函式和Invoke方法都定義了相應的引數來以注入的形式和獲取通過呼叫WebHostBuilder的ConfigureServices方法註冊的兩個服務。

   1: new WebHostBuilder()
   2:     .UseKestrel()
   3:     .ConfigureServices(svcs => svcs
   4:         .AddSingleton<IFoo, Foo>()
   5:         .AddSingleton<IBar, Bar>())
   6:     .Configure(app=>app.UseMiddleware<FoobarMiddleware>())
   7:     ...
   8:  
   9: public class FoobarMiddleware
  10: {
  11:     private RequestDelegate _next;
  12:     public FoobarMiddleware(RequestDelegate next, IFoo foo, IBar bar)
  13:     {
  14:         _next = next;
  15:         Debug.Assert(typeof(Foo).IsInstanceOfType(foo));
  16:         Debug.Assert(typeof(Bar).IsInstanceOfType(bar));
  17:     }
  18:  
  19:     public async Task Invoke(HttpContext context, IFoo foo, IBar bar)
  20:     {
  21:         Debug.Assert(typeof(Foo).IsInstanceOfType(foo));
  22:         Debug.Assert(typeof(Bar).IsInstanceOfType(bar));
  23:         await _next(context);
  24:     }
  25: }

Controller型別的建構函式中注入服務

在ASP.NET Core MVC應用中,我們經常在Controller型別的建構函式定義相應的引數來以注入的方式獲取預先註冊的服務。如下所示的這個HomeController就採用構造器注入的方式獲取通過呼叫WebHostBuilder的ConfigureServices方法註冊的兩個服務。

   1: new WebHostBuilder()
   2:     .UseKestrel()
   3:     .ConfigureServices(svcs => svcs
   4:         .AddSingleton<IFoo, Foo>()
   5:         .AddSingleton<IBar, Bar>()
   6:         .AddMvc())
   7:     .Configure(app => app.UseMvc())
   8:     ...
   9:  
  10: public class HomeController
            
           

相關推薦

ASP.NET Core如影隨形的”依賴注入”[]: 歷數依賴注入N

在對ASP.NET Core管道中關於依賴注入的兩個核心物件(ServiceCollection和ServiceProvider)有了足夠的認識之後,我們將關注的目光轉移到程式設計層面。在ASP.NET Core應用中基於依賴注入的程式設計主要涉及到兩個方面,它們分別是將服務註冊到ServiceCollect

ASP.NET Core如影隨形的”依賴注入”[上]: 從兩個不同的ServiceProvider說起

我們一致在說 ASP.NET Core廣泛地使用到了依賴注入,通過前面兩個系列的介紹,相信讀者朋友已經體會到了這一點。由於前面兩章已經涵蓋了依賴注入在管道構建過程中以及管道在處理請求過程的應用,但是內容相對分散和零碎,我們有必要針對這個主題作一個歸納性的介紹。採用依賴注入的服務均由某個ServiceProvi

ASP.NET Core使用GraphQL - 第三章 依賴注入

ASP.NET Core中使用GraphQL ASP.NET Core中使用GraphQL - 第一章 Hello World ASP.NET Core中使用GraphQL - 第二章 中介軟體 SOLID原則中的D表示依賴倒置原則。這個原則的內容是: 上層模組不應

asp.net core負載均衡場景http重定向https的問題

進行 urn 循環 == 是否 美的 err add ddr 上周欣喜地發現,微軟官方終於針對 asp.net core 在使用負載均衡的情況下從 http 強制重定向至 https 的問題提供了解決方法。 app.UseForwardedHeaders(new Fo

ASP.NET Core依賴注入(3): 服務的註冊與提供

在採用了依賴注入的應用中,我們總是直接利用DI容器直接獲取所需的服務例項,換句話說,DI容器起到了一個服務提供者的角色,它能夠根據我們提供的服務描述資訊提供一個可用的服務物件。ASP.NET Core中的DI容器體現為一個實現了IServiceProvider介面的物件。 ServiceProvider與

ASP.NET Core依賴注入(2):依賴注入(DI)

IoC主要體現了這樣一種設計思想:通過將一組通用流程的控制從應用轉移到框架之中以實現對流程的複用,同時採用“好萊塢原則”是應用程式以被動的方式實現對流程的定製。我們可以採用若干設計模式以不同的方式實現IoC,比如我們在上面介紹的模板方法、工廠方法和抽象工廠,接下來我們介紹一種更為有價值的IoC模式,即依賴注入

ASP.NET Core依賴注入(1):控制反轉(IoC)

ASP.NET Core在啟動以及後續針對每個請求的處理過程中的各個環節都需要相應的元件提供相應的服務,為了方便對這些元件進行定製,ASP.NET通過定義介面的方式對它們進行了“標準化”,我們將這些標準化的元件稱為服務,ASP.NET在內部專門維護了一個DI容器來提供所需的服務。要了解這個DI容器以及現實其中

ASP.NET Core依賴注入(4): 建構函式的選擇與服務生命週期管理

ServiceProvider最終提供的服務例項都是根據對應的ServiceDescriptor建立的,對於一個具體的ServiceDescriptor物件來說,如果它的ImplementationInstance和ImplementationFactory屬性均為Null,那麼ServiceProvider

ASP.NET Core依賴注入(5):ServicePrvider實現揭祕【補充漏掉的細節】

到目前為止,我們定義的ServiceProvider已經實現了基本的服務提供和回收功能,但是依然漏掉了一些必需的細節特性。這些特性包括如何針對IServiceProvider介面提供一個ServiceProvider物件,何建立ServiceScope,以及如何提供一個服務例項的集合。 一、提供一個Serv

ASP.NET Core依賴注入(5): ServiceProvider實現揭祕 【總體設計 】

本系列前面的文章我們主要以程式設計的角度對ASP.NET Core的依賴注入系統進行了詳細的介紹,如果讀者朋友們對這些內容具有深刻的理解,我相信你們已經可以正確是使用這些與依賴注入相關的API了。如果你還對這個依賴注入系統底層的實現原理具有好奇心,可以繼續閱讀這一節的內容。 目錄一、ServiceCall

ASP.NET Core依賴注入(5): ServiceProvider實現揭祕 【解讀ServiceCallSite 】

通過上一篇的介紹我們應該對實現在ServiceProvider的總體設計有了一個大致的瞭解,但是我們刻意迴避一個重要的話題,即服務例項最終究竟是採用何種方式提供出來的。ServiceProvider最終採用何種方式提供我們所需的服務例項取決於最終選擇了怎樣的ServiceCallSite,而服務註冊是採用的S

Asp.net core依賴注入

原文: Asp.net core中的依賴注入 使用服務 在Asp.net core的Controller中,可以通過如下兩種方式獲取系統注入的服務: 建構函式 可以直接在建構函式中傳入所依賴的服務,這是非常常見的DI注入方式。     public 

ASP.NET Core使用IOC三部曲(二.採用Autofac來替換IOC容器,並實現屬性注入)

https://www.cnblogs.com/GuZhenYin/p/8301500.html     上一篇我們說過ASP.NET Core中自帶的IOC容器是屬於輕量級的,功能並不是很多,只是提供了基礎功能而已.. 所以今天我們主要講講如何採用Autofac

ASP.NET Core 依賴項管理

伺服器端程式碼使用 Nuget 作為包管理器 對於已經習慣使用 Visual Studio 2015 作為開發工具的碼農們應該對 Nuget 不陌生,這裡不做介紹了。 但有一點需要說明,它在管理伺服器端類庫的時候確實給我們提供了很大的便利,但不可否認的是它在瀏覽器端類庫的管理上還很欠缺。 註解 如果你不

.NET Core ASP.NET Core Basic 1-2 控制反轉與依賴注入

.NET Core ASP.NET Core Basic 1-2 本節內容為控制反轉與依賴注入 簡介 控制反轉IOC 這個內容事實上在我們的C#高階篇就已經有所講解,控制反轉是一種設計模式,你可以這樣理解控制反轉,假設有一個人他有一部A品牌手機,他用手機進行聽歌、打遊戲,那麼你可以建立一個手機類和一個人類

Asp.Net Core 3.1 Api 整合Abp專案依賴注入

Abp 框架 地址https://aspnetboilerplate.com/ 我們下面來看如何在自己的專案中整合abp的功能 我們新建core 3.1 API專案和一個core類庫     然後 兩個專案都要安裝Abp Nuget Package 版本為5.1.0   如

Asp.Net CoreJson序列化處理整理

忽略 化工 res ref 工具 使用 asp.net ctr ide 一、Asp.Net Core中的Json序列化處理使用的是Newtonsoft.Json,更多參考:C# Newtonsoft.Json JsonSerializerSettings配置序列化操作,C#

ASP.NET Core 配置文件(無處不在的依賴註入)

word gist .net core closed 數據 minus [] etsec 過程 前煙:   .NET Core 中取消了以往的 XML 節點配置文件,改用了 *.json 格式。   在 Startup.cs 文件中,構造方法 build appsett

體驗 ASP.NET Core 的多語言支持(Localization)

lan expander -c blank 根據 body esp doc input 首先在 Startup 的 ConfigureServices 中添加 AddLocalization 與 AddViewLocalization 以及配置 RequestLocaliz

ASP.NET Core 使用Cookie中間件

新用戶 private 應該 validate ive mes esp tom 全選 http://ASP.NET Core 提供了Cookie中間件來序列化用戶主題到一個加密的Cookie中並且在後來的請求中校驗這個Cookie,再現用戶並且分配到HttpContext對