.Net Core使用Unity替換原生DI


一、DIP、IOC、DI

  面對對象設計原則可以幫助我們開發出更好的程序,其中有一個依賴倒置原則DIP並由此引申出IOC、DI等概念。就先粗略的了解一下:

  1. DIP(依賴倒置原則):程序要依賴於抽象接口,不要依賴於具體實現。
  2. IOC(控制反轉):面對對象編程中的一種設計思想。
  3. DI(依賴注入):組件之間依賴關系由容器在運行期決定。

  總的來說控制反轉(IoC)是依賴倒置原則(DIP)的實現思路;依賴注入(DI)又是IoC的一種實現方式。

二、Unity

  Unity容器(Unity)是一個輕量級,可擴展的依賴注入容器。它有助於構建松散耦合的應用程序,並為開發人員提供以下優勢:

  1. 簡化對象創建,尤其是對於分層對象結構和依賴項
  2. 抽象要求; 這允許開發人員在運行時或配置中指定依賴關系,並簡化橫切關注點的管理
  3. 通過將組件配置推遲到容器來提高靈活性
  4. 服務定位能力; 這允許客戶端存儲或緩存容器
  5. 實例和類型攔截
  6. 按慣例注冊

三、Unity替換.Net Core原生DI

  關於Unity替換.Net Core原聲DI我發現在網上的中文資料基本沒有,所以我在Unity的Gitbub上找到了相關的內容,希望可以給大家帶來幫助。

  我的是.Net Core2.2首先需要通過Nuget引入Unity(5.10.2)和Unity.Microsoft.DependencyInjection(5.10.1)這里需要注意版本,我原先Unity引用5.10.3的就運行報錯了。

  在Program.cs文件中的CreateWebHostBuilder中添加UseUnityServiceProvider()方法即可替換.Net Core的原生DI容器,具體如下:

        private static IUnityContainer _container;
        public static void Main(string[] args)
        {
            _container = new UnityContainer();
            ConfigureContainer(_container);
            CreateWebHostBuilder(args).Build().Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseUnityServiceProvider(_container)
                .UseStartup<Startup>();

        public static void ConfigureContainer(IUnityContainer _container)
        {
        //注冊對象關系
        }

 四、Unity的二種對象關系注冊

  1、代碼實現

  使用代碼主要分為以下兩步:

  1. 創建一個UnityContainer對象。
  2. 通過UnityContainer對象的RegisterType方法來注冊對象與對象之間的關系
    IUnityContainer _container = new UnityContainer();
    _container.RegisterType<IPhone, NubiaPhone>();
    _container.RegisterType<IPhone, MiPhone>("Mi");
    _container.RegisterType<IEarPhone, NubiaEarPhone>();

   2、使用配置文件

  使用配置文件需要引用Unity.Configuration,由於項目龐大的情況下配置文件會變得很多,所以我這里單獨拿出來一個文件進行配置。主要分為以下三步:

  1. 在配置文件中<configSections> 配置節下unity注冊。
  2. 在<configuration> 配置節下添加Unity配置信息。
  3. 在代碼中讀取配置信息,並將配置載入到UnityContainer中。

  配置文件如下:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Unity.Configuration"/>
  </configSections>
  <unity>
    <typeAliases>
      <typeAlias alias="IEarPhone" type="Xu.UnityDemo.Interface.IEarPhone,Xu.UnityDemo" />
      <typeAlias alias="IPhone" type="Xu.UnityDemo.Interface.IPhone,Xu.UnityDemo" />
      <typeAlias alias="NubiaPhone" type="Xu.UnityDemo.Model.NubiaPhone,Xu.UnityDemo" />
      <typeAlias alias="MiPhone" type="Xu.UnityDemo.Model.MiPhone,Xu.UnityDemo" />
      <typeAlias alias="NubiaEarPhone" type="Xu.UnityDemo.Model.NubiaEarPhone,Xu.UnityDemo" />
      <typeAlias alias="MiEarPhone" type="Xu.UnityDemo.Model.MiEarPhone,Xu.UnityDemo" />
    </typeAliases>
    <containers>
      <container name="IOCcontainer">
        <type type="IPhone" mapTo="MiPhone" name="Mi"></type >
        <type type="IPhone" mapTo="NubiaPhone"></type >
        <type type="IEarPhone" mapTo="NubiaEarPhone"></type >
      </container>
    </containers>
  </unity>
</configuration>

   主要用到兩個節點<typeAlias>和<type>。<typeAlias>節點的alias是別名在<type>節點中的type使用,type是“命名空間+對象名,所在程序集名稱”。<type>節點的type是“需要映射的對象”mapTo是“映射的目標對象”name是“標識名”在多個類繼承同個接口的時候區分使用。其余的節點如圖Unity配置文件節點圖

  代碼如下:

ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = Directory.GetCurrentDirectory() + "/Config/UnityIocConfig.xml";
Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
UnityConfigurationSection section = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName);
//獲取特定配置節下已命名的配置節<container name="IOCcontainer">下的配置信息
section.Configure(_container, "IOCcontainer");

 五、三種依賴注入

  1、構造函數注入

  構造函數注入是最常用的一種注入方式,如下:

        private IPhone _iPhone;
        private IUnityContainer _container;
        public ValuesController(IUnityContainer container, IPhone iPhone)
        {
            _container = container;
            _iPhone = iPhone;
        }

   此處我在ValuesController控制器寫了一個構造函數,container注入的對象就是在UseUnityServiceProvider()方法中傳入的Unity容器對象,我們通過Resolve<T>()方法可以直接使用。iPhone也會被注入NubiaPhone類。當然也可以在別的類中使用如下:

        [InjectionConstructor]
        public NubiaPhone(IEarPhone earPhone)
        {
            earPhone.Color = "blue";
        }

   當存在多個構造函數的時候,如果有[InjectionConstructor]特性標記則使用此構造函數,否則選擇參數最多的那個。

  2、屬性注入

  屬性注入需要在屬性上標記[Dependency]特性,[Dependency]可以指定一個name標識名來指定注入屬性的具體對象。

        [Dependency("name")]
        public IEarPhone _iEarPhone { set; get; }

  3.方法注入

  方法注入需要標記[InjectionMethod]特性,使用和構造函數注入相似。

        [InjectionMethod]
        public void Init(IEarPhone iEarPhone)
        {
            _iEarPhone = iEarPhone;
        }

 六、總結

  很多內容我沒有細講,因為很多東西內容都在園中可以找到,我主要是為了解決Unity替換Net Core原生DI的問題。希望大家有問題可以交流共勉。我的測試代碼


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM