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

来源:http://www.cnblogs.com/artech/archive/2016/11/25/di-asp-net-core-pipeline-2.html
-Advertisement-
Play Games

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


在對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
	   

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.查看目錄 Ctrl+L 2.在終端下:複製命令:Ctrl + Shift + C 組合鍵.粘貼命令:Ctrl + Shift + V 組合鍵. 3.解壓 tar xzf flie.tar.gz 4.mkdir 文件夾 --/創建一個文件夾rmdir 空文件夾名 --/刪除一個空文件夾rm 文件名 ...
  • 上一遍又說到Godaddy 生請證書流程與操作; 現因使用Incapsula 防護使用到https,在添加網站時需要自定義證書,其中需要上傳私鑰信息,因公鑰是能過keytool 生成所以需要導出私鑰信息; 導出的步驟如下: 一:安裝openssl and openssl-devel: 二:能過key ...
  • centos7 字元界面操作基礎 1.字元界面的使用方法 2.本地登錄和遠程登錄 3.學會使用putty 4.理解系統運行級別及其切換方法 5.掌握常用的系統關機和重啟命令 為什麼使用字元工作方式? 1.在字元操作方式下可以高效的完成所有的任務,尤其是系統管理任務。 2.系統管理任務通常都是遠程進行 ...
  • Hyper-V是微軟的管理虛擬機(Virtual Machine)的服務,在安裝Hyper-V功能之後,系統自動安裝可視化的虛擬機管理工具:Hyper-V Manager。在同一臺物理機上,能夠使用Hyper-V創建多個虛擬機(VM),每一個VM執行不同的工作負載(workload),運行單獨的系統 ...
  • linux的特點 優點: 1、免費的/開源的系統 2、支持多線程/多用戶的系統 3、安全性好 4、對記憶體和文件管理優越 5、提供了豐富的網路功能 6、良好的用戶界面。圖形化界面和字元型界面 linux體積最少只需要記憶體4M,由於小所以可以做嵌入式開發 linux系統的組成: 內核:是系統的心臟,實現 ...
  • 若虛擬機在不正常關機的時候會遇到如下圖所示的問題:先點擊“取消”按鈕 解決方法:打開“資源管理器”,進入到彈出提示視窗所在的路徑(即H:\VMware\Virtual Machines Documents\CentOS),在這裡找到CentOS.vmx.lck文件夾,然後將尾碼名.lck的文件夾刪除 ...
  • 1.參照Zabbix文檔配置 依照官方文檔配置,沒什麼說的。 zabbix官方文檔:https://www.zabbix.com/documentation/3.2/manual/vm_monitoring 2.遇到的問題 這裡主要介紹我遇到的問題。由於理解偏差,文檔中的sdk,我以為是sdk的意思... ...
  • 問題 怎麼樣可以使用更貼近資源(Controller,Action)的方式定義路由。 解決方案 可以使用屬性路由直接在資源級別聲明路由。只要簡單的在 Action 上使用屬性路由 RouteAttribute,然後傳一個相關路由模板就可以。屬性路由與集中式路由在路由模板含義上基本是一樣的,所有路由參 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...