依賴注入之Autofac使用總結

2022-01-08 dotNET跨平臺

依賴倒置?控制反轉(IOC)? 依賴注入(DI)?

你是否還在被這些名詞所困擾,是否看了大量理論文章後還是一知半解了?

今天我想結合實際項目,和正在迷惑中的新手朋友一起來學習和總結依賴注入Autofac的使用和理解。

依賴注入粗暴理解依賴: 

public class A{
public void A(B b) {
// do something } }

這樣的代碼,估計沒有程序猿不曾使用。

A類實例化的時候需要一個B的對象作為構造函數的參數,那麼A就依賴B,這就叫依賴。

當然,不用構造函數的方式,在A類內部去new一個B,其實也是一樣存在A依賴B。

注入:

看到「注入」一詞,第一想到的是不是注射器?哈哈,還生活在童年陰影中。 結合一下「打針」這個場景來簡單理解下依賴注入。
醫生使用注射器(Autofac),將藥物(依賴=類對象),注入到血管(其他類中)。

Autofac的基本使用搭建項目

創建一個MVC項目,通過Nuget直接添加Autofac。

 注入類本身.AsSelf()

public class TestController : Controller {

private readonly InjectionTestService _testService;

public TestController(InjectionTestService testService) { _testService = testService; }

public ActionResult Index() { ViewBag.TestValue = _testService.Test();
return View(); } }

public class InjectionTestService : IService { public string Test() { return "Success"; } }

在Global.asax中加入依賴注入的註冊代碼

// 創建一個容器 var builder = new ContainerBuilder(); // 註冊所有的Controller builder.RegisterControllers(Assembly.GetExecutingAssembly()); // RegisterType方式: builder.RegisterType<InjectionTestService>().AsSelf().InstancePerDependency(); // Register方式: builder.Register(c => new InjectionTestService()).AsSelf().InstancePerDependency(); // 自動注入的方式,不需要知道具體類的名稱 /* BuildManager.GetReferencedAssemblies()             * 程序集的集合,包含 Web.config 文件的 assemblies 元素中指定的程序集、             * 從 App_Code 目錄中的自定義代碼生成的程序集以及其他頂級文件夾中的程序集。             */ // 獲取包含繼承了IService接口類的程序集 var assemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>() .Where( assembly => assembly.GetTypes().FirstOrDefault(type => type.GetInterfaces().Contains(typeof(IService))) != null ); // RegisterAssemblyTypes 註冊程序集 var enumerable = assemblies as Assembly[] ?? assemblies.ToArray();
if (enumerable.Any()) { builder.RegisterAssemblyTypes(enumerable) .Where(type => type.GetInterfaces().Contains(typeof(IService))).AsSelf().InstancePerDependency(); } // 把容器裝入到微軟默認的依賴注入容器中 var container = builder.Build(); DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

為接口注入具體類.AsImplementedInterfaces()

public class TestController : Controller {
private readonly IService _testService;
public TestController(IService testService) { _testService = testService; } public ActionResult Index() { ViewBag.TestValue = _testService.Test();
return View(); } }

// Register 方式指定具體類 builder.Register(c => new InjectionTestService()).As<IService>().InstancePerDependency(); // RegisterType 方式指定具體類 builder.RegisterType<InjectionTestService>().As<IService>().InstancePerDependency(); // 自動註冊的方式            // 獲取包含繼承了IService接口類的程序集 var assemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>() .Where( assembly => assembly.GetTypes().FirstOrDefault(type => type.GetInterfaces().Contains(typeof(IService))) != null ); // RegisterAssemblyTypes 註冊程序集 var enumerable = assemblies as Assembly[] ?? assemblies.ToArray();
if (enumerable.Any()) { builder.RegisterAssemblyTypes(enumerable) .Where(type => type.GetInterfaces().Contains(typeof(IService))).AsImplementedInterfaces().InstancePerDependency(); }

 利用Named自動注入依賴類

需求場景說明:

有A、B、C三個簡訊平臺提供發送簡訊業務;

分別有三個簡訊平臺的實現類,AMessage,BMessage,CMessage;

客戶端在不同時段選取不同平臺發送簡訊。

常規簡單處理方式

新建三個服務類,AMsgService,BMsgService,CMsgService。
在客戶端通過 if else 的方式判斷要選用哪個簡訊平臺,然後new服務類對象,再調用Send方法發送簡訊。

缺點

如果有新的簡訊平臺D加入的話,必須新建一個DSendMsgService,然後修改客戶端if else 代碼。

改造

抽象一個簡訊平臺的接口

public interface IMessage {
decimal QueryBalance();
bool Send(string msg);
int TotalSend(DateTime? startDate, DateTime? endDate); }

 具體實現類

[MessagePlatform(Enums.MPlatform.A平臺)]
public class ASendMessageService : IMessage { public decimal QueryBalance() { return 0; } public bool Send(string msg) { return true; } public int TotalSend(DateTime? startDate, DateTime? endDate) { return 100; } }

類有一個自定義屬性標籤MessagePlatform,這個是幹嘛了? 是為了給這個類做一個標記,結合Named使用,實現自動注入。

public class TestController : Controller {
private Func<int, IMessage> _factory;
public TestController(Func<int, IMessage> factory) { _factory = factory; }
public ActionResult Index() {
var retult = _factory((int)Enums.MPlatform.A平臺).Send("去你的吧");
return View(retult); } }

構造函數參數居然是一個func的委託?

這個factory傳入參數是一個int(定義好的簡訊平臺枚舉值),就可以拿到這個簡訊平臺具體的實現類?

沒錯,autofac就是這麼任性。

builder.RegisterType<ASendMessageService>().Named<IMessage>( ( // 獲取類自定義屬性 typeof(ASendMessageService).GetCustomAttributes(typeof(MessagePlatformAttribute), false).FirstOrDefault() as MessagePlatformAttribute ).platform.ToString() ).InstancePerRequest(); builder.Register<Func<int, IMessage>>(c => { var ic = c.Resolve<IComponentContext>(); return name => ic.ResolveNamed<IMessage>(name.ToString()); });

疑問:

上面只是給 ASendMessageService類實現了自動注入,那麼BSendMessageService,CSendMessageService怎麼辦了,不可能都去複製一段注入的配置代碼吧?

typeof(IMessage).Assembly.GetTypes() .Where(t => t.GetInterfaces().Contains(typeof(IMessage))) .ForEach(type => { // 註冊type });

如果你有些實現類不在IMessge這個程序集下,那就不能這麼寫了,要結合具體項目情況來調整代碼。

總結

1.依賴注入的目的是為了解耦。

2.不依賴於具體類,而依賴抽象類或者接口,這叫依賴倒置。

3.控制反轉即IoC (Inversion of Control),它把傳統上由程序代碼直接操控的對象的調用權交給容器,通過容器來實現對象組件的裝配和管理。所謂的「控制反轉」概念就是對組件對象控制權的轉移,從程序代碼本身轉移到了外部容器。

4. 微軟的DependencyResolver如何創建controller 【後續學習】

Autofac創建類的生命周期

1、InstancePerDependency

對每一個依賴或每一次調用創建一個新的唯一的實例。這也是默認的創建實例的方式。

官方文檔解釋:Configure the component so that every dependent component or call to Resolve() gets a new, unique instance (default.) 

2、InstancePerLifetimeScope

在一個生命周期域中,每一個依賴或調用創建一個單一的共享的實例,且每一個不同的生命周期域,實例是唯一的,不共享的。

官方文檔解釋:Configure the component so that every dependent component or call to Resolve() within a single ILifetimeScope gets the same, shared instance. Dependent components in different lifetime scopes will get different instances. 

3、InstancePerMatchingLifetimeScope

在一個做標識的生命周期域中,每一個依賴或調用創建一個單一的共享的實例。打了標識了的生命周期域中的子標識域中可以共享父級域中的實例。若在整個繼承層次中沒有找到打標識的生命周期域,則會拋出異常:DependencyResolutionException。

官方文檔解釋:Configure the component so that every dependent component or call to Resolve() within a ILifetimeScope tagged with any of the provided tags value gets the same, shared instance. Dependent components in lifetime scopes that are children of the tagged scope will share the parent's instance. If no appropriately tagged scope can be found in the hierarchy an DependencyResolutionException is thrown. 

4、InstancePerOwned

在一個生命周期域中所擁有的實例創建的生命周期中,每一個依賴組件或調用Resolve()方法創建一個單一的共享的實例,並且子生命周期域共享父生命周期域中的實例。若在繼承層級中沒有發現合適的擁有子實例的生命周期域,則拋出異常:DependencyResolutionException。

官方文檔解釋:Configure the component so that every dependent component or call to Resolve() within a ILifetimeScope created by an owned instance gets the same, shared instance. Dependent components in lifetime scopes that are children of the owned instance scope will share the parent's instance. If no appropriate owned instance scope can be found in the hierarchy an DependencyResolutionException is thrown. 

5、SingleInstance

每一次依賴組件或調用Resolve()方法都會得到一個相同的共享的實例。其實就是單例模式。

官方文檔解釋:Configure the component so that every dependent component or call to Resolve() gets the same, shared instance. 

6、InstancePerHttpRequest  (新版autofac建議使用InstancePerRequest)

在一次Http請求上下文中,共享一個組件實例。僅適用於asp.net mvc開發。

官方文檔解釋:Share one instance of the component within the context of a single HTTP request.

 

 參考文檔:
https://stackoverflow.com/questions/2888621/autofacs-funct-to-resolve-named-service

http://blog.csdn.net/dhx20022889/article/details/9061483

相關文章:

原文地址:http://www.cnblogs.com/struggle999/p/6986903.html

.NET社區新聞,深度好文,微信中搜索dotNET跨平臺或掃描二維碼關注

相關焦點

  • 使用 Autofac 進行依賴注入
    突然有一天發現依賴注入這種技能。為了使得架構可測試、易維護、可擴展,需要架構設計為鬆耦合類型,簡單的說也就是解耦。    原文地址:http://www.codeproject.com/Articles/25380/Dependency-Injection-with-Autofac--Dependency Injection with Autofac使用 Autofac 進行依賴注入目錄Introduction-介紹Autofac
  • 一文讀懂ASP.NET Core 依賴注入
    1、首先在ASP.NET Core中是支持依賴注入軟體設計模式,或者說依賴注入是ASP.NET Core的核心;2、依賴注入(DI)和控制反轉(IOC)基本是一個意思,因為說起來誰都離不開誰;或者可以說他們是同一個概念的不同角度描述;3、軟體設計原則中有一個依賴倒置原則(DIP),就是為了解耦
  • 一文讀懂Asp.net core 依賴注入(Dependency injection)
    一、什麼是依賴注入首先在Asp.net core中是支持依賴注入軟體設計模式,或者說依賴注入是asp.net core的核心
  • .net core 依賴注入: 什麼是控制反轉,什麼是依賴注入,什麼是容器, autofac 簡單使用
    綜述ASP.NET Core  支持依賴注入, 也推薦使用依賴注入. 主要作用是用來降低代碼之間的耦合度.
  • Autofac框架初識與應用
    一、前言這上一篇中,主要講述了什麼是IoC容器,以及了解到它是DI構造函注入的框架,它管理著依賴項的生命周期以及映射關係,同時也介紹實踐了在ASP.Net Core中,默認提供的內置IoC容器,以及它的實例註冊方式和相應的生命周期。
  • WebAPI使用依賴注入
    (點擊上方藍字,可快速關注我們)來源:神牛步行3cnblogs.com/wangrudong003/p/6253486.html本篇將要和大家分享的是webapi中如何使用依賴注入,依賴注入這個東西在接口中常用,實際工作中也用的比較頻繁,因此這裡分享兩種在api中依賴注入的方式Ninject和Unity。
  • Android Hilt依賴注入框架的使用
    中國移動家庭運營中心融合通信 閆同學一、什麼是依賴注入?依賴注入是一個聽起來很「高大上」的概念,但是其實很簡單。本來我要接受各種參數自己構造一個對象,現在只接受一個已經實例化的對象直接作為參數。所謂依賴注入,其實就是之前在類的內部自己構造成員變量,現在放到了外部構造成員變量。而Hilt,其實就是Android基於Dragger開發的一套Android上的依賴注入框架而已。
  • 依賴注入與對象間的關係
    依賴注入 vs 創建對象有不少地方這樣描述:「依賴注入改變了使用對象前先創建的傳統方式,而是從外部注入依賴的對象」。應該說這是一種合理的設計,但如果接本段開頭的話說「依賴注入改變了人使用汽車之前先創建的傳統方式」您會不會覺得別捏呢?
  • 使用Yii2依賴注入簡化開發
    什麼是依賴注入(DI)?對象由框架來創建而不是程式設計師通過 new 創建。
  • 依賴注入和控制反轉
    誰依賴於誰:當然是某個對象依賴於IoC/DI的容器為什麼需要依賴:對象需要IoC/DI的容器來提供對象需要的外部資源誰注入於誰:很明顯是IoC/DI的容器 注入 某個對象到底注入什麼:就是注入某個對象所需要的外部資源誰控制誰:當然是IoC/DI的容器來控制對象了控制什麼:主要是控制對象實例的創建為何叫反轉
  • 開發(三) 依賴注入
    簡單來講,它是使用大型的類型解析容器來解析類的依賴的一種方式。幾乎每一種現代化的程式語言都有很多的與之對應的依賴注入框架。我們重點關注C#語言,它也有很多的依賴注入框架,像是Ninject,AutoFac,Unity( Microsoft),還有很多其他的。
  • 依賴注入和控制反轉的理解
    ●為何是反轉,哪些方面反轉了:有反轉就有正轉,傳統應用程式是由我們自己在對象中主動控制去直接獲取依賴對象,也就是正轉;而反轉則是由容器來幫忙創建及注入依賴對象;為何是反轉?因為由容器幫我們查找及注入依賴對象,對象只是被動的接受依賴對象,所以是反轉;哪些方面反轉了?依賴對象的獲取被反轉了。
  • XUnit 依賴注入
    Intro現在的開發中越來越看重依賴注入的思想,微軟的 Asp.Net Core 框架更是天然集成了依賴注入,那麼在單元測試中如何使用依賴注入呢?本文主要介紹如何通過 XUnit 來實現依賴注入, XUnit 主要藉助 SharedContext 來共享一部分資源包括這些資源的創建以及釋放。
  • 我曾想深入了解的:依賴倒置、控制反轉、依賴注入
    這一次,我想深入了解和探討我曾經很迷糊,也沒有一直仔細了解的:依賴倒置、控制反轉、依賴注入 這些概念。什麼是依賴?通常可以理解為一種需要,需求。需要協助才能完成一件事情。什麼是依賴注入呢?其實我們剛剛已經實現過了,全文先是依賴倒置,然後控制反轉,而現在說的依賴注入是控制反轉的具體實現方式。依賴注入是解開依賴並實現反轉的一種手段。
  • 理解JavaScript中的依賴注入
    JavaScript也不例外,在我們使用JavaScript編寫應用時,我們是不是都會使用到別人編寫的代碼,例如一些著名的開源庫或者框架。隨著我們項目的增長,我們需要依賴的模塊變得越來越多,這個時候,如何有效的組織這些模塊就成了一個非常重要的問題。依賴注入解決的正是如何有效組織代碼依賴模塊的問題。
  • 聊聊依賴注入註解@Resource和@Autowired
    前言@Resource和@Autowired註解都可以在Spring Framework應用中進行聲明式的依賴注入。而且面試中經常涉及到這兩個註解的知識點。今天我們來總結一下它們。2.該註解使用在成員屬性和 setter 方法上。默認情況下@Resource按照名稱注入,如果沒有顯式聲明名稱則按照變量名稱或者方法中對應的參數名稱進行注入。
  • 那些年搞不懂的高深術語:依賴倒置•控制反轉•依賴注入•面向接口編程
    由此我們也可以總結出開發框架與類庫的區別:使用開發框架時,框架掌握程序流程的控制權,而使用類庫時,則是應用程式掌握程序流程的控制權。依賴注入(Dependency Injection)依賴注入與依賴倒置、控制反轉的關係仍舊是一本萬殊。依賴注入,就其廣義而言,即是通過「注入」的方式,來獲得依賴。我們知道,A對象依賴於B對象,等價於A對象內部存在對B對象的「調用」,而前提是A對象內部拿到了B對象的引用。
  • 更優雅的在 Xunit 中使用依賴注入
    Xunit.DependencyInjection 7.0 發布了Intro上次我們已經介紹過一次大師的 Xunit.DependencyInjection  在 Xunit 中使用依賴注入 ,最近大師完成了 7.0 的重構並且已經正式發布,已經可以直接安裝使用了7.0 為我們帶來了更好的編程體驗
  • golang依賴注入工具wire指南
    wire與依賴注入 Wire 是一個的Golang依賴注入工具,通過自動生成代碼的方式在編譯期完成依賴注入,Java體系中最出名的Spring框架採用運行時注入,個人認為這是wire和其他依賴注入最大的不同之處。
  • 詳解 Python 中的類型化函數依賴注入
    關於如何使用DI框架,有一些已知的問題、技巧乃至一整套相關的方法論。很多人問我:如何將許多類型化的函數概念與傳統的面向對象依賴注入結合使用?這個問題很有意義。因為函數式編程都是關於組合的。依賴注入只是個魔術。你會在代碼的某些地方注入一些幾乎隨機的對象,之後,被注入的整個容器在運行時由各個部分神奇地組裝而成。