亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

.NET用Unity依賴注入——概述注冊和解析類型(1)

2019-11-14 16:03:58
字體:
來源:轉載
供稿:網友

本文內容

  • Unity 概述
  • 環境
  • 一個真實的例子
  • 類型注冊(Type Registrations)
  • 解析類型(Resolving Types)

跳槽,新公司使用了 Unity,初步看了一下,公司的使用還是比較簡單的,其實 Unity 本身的用法很多。另外,前段時間我翻譯和實驗了 Martin Fowler 的《java 控制反轉和依賴注入模式》,本文是 .NET 平臺下的依賴注入。

Unity 涉及的內容和用法比較多,之后慢慢說,本文先大概介紹如何用 Unity 進行依賴注入,它基本可以分為兩個操作:注冊(RegisterType)和解析(Resolve),也就是說,先注冊類型;然后解析類型,返回創建的對象。

下載 MyDemo and DIwithUnitySample

下載 MyDemo and DIwithUnitySample v2(補充)

下載 Unity 3

下載 Unity bootstrapper for asp.net MVC

下載 Unity bootstrapper for ASP.NET WebApi

Unity 概述


Unity application Block(Unity)是一個輕量級的,可擴展的依賴注入容器,它支持構造函數注入,屬性注入和方法調用注入。它為開發人員提供了以下優點:

  • 提供簡化的對象創建,特別是層級對象結構和依賴,簡化應用程序代碼;
  • 支持需求抽象;這可以讓開發者在運行時或是配置文件指定依賴,簡化橫切關注點(crosscutting concerns)的管理;
  • 通過延遲組件配置到容器,增加了靈活性;
  • 具有服務定位器功能;這可以讓客戶存儲或緩存容器。對 ASP.NET Web 應用程序特別有用,開發者可以在 ASP.NET 會話或應用程序中持久容器。

環境


  • Windows 7 旗艦版 SP1
  • Microsoft Visual Studio Ultimate 2013 Update 4

一個真實的例子


咋看上去,RegisterTypes 方法有點復雜;下面會詳細討論各種的類型注冊;再討論應用程序如何注冊以在運行時需要時解析類型。這個例子也說明,在你應用程序的一個方法內如何完成所有類型的注冊。

public static void RegisterTypes(IUnityContainer container)
        {
            Trace.WriteLine(string.Format("Called RegisterTypes in ContainerBootstrapper"), "UNITY");
 
            var storageAccountType = typeof(StorageAccount);
            var retryPolicyFactoryType = typeof(IRetryPolicyFactory);
 
            // 實例注冊
            StorageAccount account =
              ApplicationConfiguration.GetStorageAccount("DataConnectionString");
            container.RegisterInstance(account);
 
            // 注冊工廠
            container
              .RegisterInstance<IRetryPolicyFactory>(new ConfiguredRetryPolicyFactory())
              .RegisterType<ISurveyAnswerContainerFactory, SurveyAnswerContainerFactory>(new ContainerControlledLifetimeManager());
 
            // 注冊 table 類型
            container
              .RegisterType<IDataTable<SurveyRow>, DataTable<SurveyRow>>(new InjectionConstructor(storageAccountType, retryPolicyFactoryType, Constants.SurveysTableName))
              .RegisterType<IDataTable<QuestionRow>, DataTable<QuestionRow>>(new InjectionConstructor(storageAccountType, retryPolicyFactoryType, Constants.QuestionsTableName));
 
            // 注冊 message queue 類型, 使用帶泛型的 typeof
            container
              .RegisterType(
                  typeof(IMessageQueue<>),
                  typeof(MessageQueue<>),
                  new InjectionConstructor(storageAccountType, retryPolicyFactoryType, typeof(String)));
 
            // 注冊 blob 類型
            container
              .RegisterType<IBlobContainer<List<string>>,
                EntitiesBlobContainer<List<string>>>(
                  new InjectionConstructor(storageAccountType, retryPolicyFactoryType, Constants.SurveyAnswersListsBlobName))
              .RegisterType<IBlobContainer<Tenant>,
                EntitiesBlobContainer<Tenant>>(
                  new InjectionConstructor(storageAccountType, retryPolicyFactoryType, Constants.TenantsBlobName))
              .RegisterType<IBlobContainer<byte[]>,
                FilesBlobContainer>(
                  new InjectionConstructor(storageAccountType, retryPolicyFactoryType, Constants.LogosBlobName, "image/jpeg"))
              .RegisterType<IBlobContainer<SurveyAnswer>,
                EntitiesBlobContainer<SurveyAnswer>>(
                  new InjectionConstructor(storageAccountType, retryPolicyFactoryType, typeof(String)));
 
            // 注冊 store 類型
            container
              .RegisterType<ISurveyStore, SurveyStore>()
              .RegisterType<ITenantStore, TenantStore>()
              .RegisterType<ISurveyAnswerStore, SurveyAnswerStore>(
                new InjectionFactory((c, t, s) => new SurveyAnswerStore(
                  container.Resolve<ITenantStore>(),
                  container.Resolve<ISurveyAnswerContainerFactory>(),
                  container.Resolve<IMessageQueue<SurveyAnswerStoredMessage>>(new ParameterOverride("queueName", Constants.StandardAnswerQueueName)),
                  container.Resolve<IMessageQueue<SurveyAnswerStoredMessage>>(new ParameterOverride("queueName", Constants.PRemiumAnswerQueueName)),
                  container.Resolve<IBlobContainer<List<String>>>())));
        }

類型注冊(Type Registrations)


上面的代碼列出了用 Unity 容器完成不同類型的注冊。下面單獨說明。

實例注冊

最簡單的類型注冊就是實例注冊,Unity 容器以單件實例來負責維護對象的引用。例如:

StorageAccount account =
              ApplicationConfiguration.GetStorageAccount("DataConnectionString");
            container.RegisterInstance(account);

StorageAccount 對象在注冊時間就被創建,并且在容器中只有一個該對象的實例。這個單獨的實例被容器中很多其他對象共享。

你也可以在 RegisterType 方法中使用 ContainerControlledLifetimeManager 類來創建單件實例,有容器維護對象的引用。

簡單類型注冊

最常見的類型注冊是把一個接口類型映射到一個具體的類型。例如:

container.RegisterType<ISurveyStore, SurveyStore>();

接下來,你可以按如下代碼解析 ISurveyStore 類型,容器將把任何所需的依賴注入到 SurveyStore 對象,并創建。

var surveyStore = container.Resolve<ISurveyStore>();

構造函數注入

下面的代碼段說明 DataTable 類的具有三個參數的構造函數。

public DataTable(StorageAccount account, IRetryPolicyFactory retryPolicyFactory, string tableName)
    : base(retryPolicyFactory)
{
    Trace.WriteLine(string.Format("Called constructor in DataTable with account={0}, tableName={1}", account.ConnectionString, tableName), "UNITY");
    this.account = account;
    this.tableName = tableName;
}

在容器中注冊 DataTable 類型會包含一個容器如何解析參數類型的 InjectionConstructor 定義:Storage-Account 和 RetryPolicyFactory 類型,以及表名。

container
             .RegisterType<IDataTable<SurveyRow>, DataTable<SurveyRow>>(new InjectionConstructor(storageAccountType, retryPolicyFactoryType, Constants.SurveysTableName))
             .RegisterType<IDataTable<QuestionRow>, DataTable<QuestionRow>>(new InjectionConstructor(storageAccountType, retryPolicyFactoryType, Constants.QuestionsTableName));

blob 類型也使用類似的方法:

container
              .RegisterType<IBlobContainer<List<string>>,
                EntitiesBlobContainer<List<string>>>(
                  new InjectionConstructor(storageAccountType, retryPolicyFactoryType, Constants.SurveyAnswersListsBlobName))
              .RegisterType<IBlobContainer<Tenant>,
                EntitiesBlobContainer<Tenant>>(
                  new InjectionConstructor(storageAccountType, retryPolicyFactoryType, Constants.TenantsBlobName))
              .RegisterType<IBlobContainer<byte[]>,
                FilesBlobContainer>(
                  new InjectionConstructor(storageAccountType, retryPolicyFactoryType, Constants.LogosBlobName, "image/jpeg"))
              .RegisterType<IBlobContainer<SurveyAnswer>,
                EntitiesBlobContainer<SurveyAnswer>>(
                  new InjectionConstructor(storageAccountType, retryPolicyFactoryType, typeof(String)));

這里的 blob,跟實際數據庫中的 Binary Lob 無關。

除了構造函數注入外,Unity 也支持屬性和方法注冊。如果你使用屬性注入,應該確保屬性具有默認值。這個很容易忘記。

注冊開放泛型

下面代碼段使用稍微不同的方法注冊 MessageQueue 類型:它使用 RegisterTypes 方法的一個重載。

container
             .RegisterType(
                 typeof(IMessageQueue<>),
                 typeof(MessageQueue<>),
                 new InjectionConstructor(storageAccountType, retryPolicyFactoryType, typeof(String)));

所謂“開放的泛型”,是泛型的尖括號里沒有內容。

該方法使你用任何參數解析 MessageQueue 類型。下面代碼段使用 SurveyAnswerStoredMessage 類型:

container.Resolve<IMessageQueue<SurveyAnswerStoredMessage>>(...);

參數覆蓋

本文最開始的代碼中,InjectionConstructor 構造函數的其中一個參數是 typeof(string)。如下所示:

container
              .RegisterType(
                  typeof(IMessageQueue<>),
                  typeof(MessageQueue<>),
                  new InjectionConstructor(storageAccountType, retryPolicyFactoryType, typeof(String)));
……
container
             .RegisterType<IBlobContainer<SurveyAnswer>,
               EntitiesBlobContainer<SurveyAnswer>>(
                 new InjectionConstructor(storageAccountType, retryPolicyFactoryType, typeof(String)));

容器不包括解決這種類型的注冊。這提供了一個方便的方法來傳遞在注冊時未知的參數值,容器通過 ParameterOverride 類型來創建實例。

解析類型(Resolving Types)


可以在三個地方完成注冊:在初始化存儲的一個單獨的應用程序(a standalone application that initializes the storage),在 Web 應用程序的開始階段(web application’s start-up phase),以及一個工廠類(factory class)。

簡單解析

在簡單的獨立的應用程序中使用很簡單:調用 RegisterTypes 方法完成注冊,解析對象,然后調用它們的 Initialize 方法完成初始化工作。如下所示:

static void Main(string[] args)
{
    TextWriterTraceListener tr1 = new TextWriterTraceListener(System.Console.Out);
    Debug.Listeners.Add(tr1);
 
    using (var container = new UnityContainer())
    {
        Console.WriteLine("# Performing Registrations...");
        ContainerBootstrapper.RegisterTypes(container);
        Console.WriteLine("Container has {0} Registrations:",
              container.Registrations.Count());
        foreach (ContainerRegistration item in container.Registrations)
        {
            Console.WriteLine(item.GetMappingAsString());
        }
        Console.WriteLine();
        Console.WriteLine("# Performing type resolutions...");
        container.Resolve<ISurveyStore>().Initialize();
        container.Resolve<ISurveyAnswerStore>().Initialize();
        container.Resolve<ITenantStore>().Initialize();
 
        Console.WriteLine("Done");
        Console.ReadLine();
    }
}

Initialization 方法執行后,容器會被釋放。

在一個 MVC 應用程序中解析

在 MVC 應用程序中的使用更要復雜點:應用程序配置容器,這樣應用程序在啟動時就會使用,之后,解析各種類型。記住,這是 ASP.NET MVC 應用程序;因此,容器必須能注入 MVC 控制器類。“Unity bootstrapper for ASP.NET MVC”NuGet package 簡化了這些。當你將該包添加到你的項目后,會生成一個 UnityConfig 類,下面代碼段說明該類的注冊方法。你可以選擇從你的應用程序文件加載 Unity 配置或直接添加注冊。

using System;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
 
namespace UnityBootstrapperForMVCDemo.App_Start
{
    /// <summary>
    /// Specifies the Unity configuration for the main container.
    /// </summary>
    public class UnityConfig
    {
        #region Unity Container
        private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
        {
            var container = new UnityContainer();
            RegisterTypes(container);
            return container;
        });
 
        /// <summary>
        /// Gets the configured Unity container.
        /// </summary>
        public static IUnityContainer GetConfiguredContainer()
        {
            return container.Value;
        }
        #endregion
 
        /// <summary>Registers the type mappings with the Unity container.</summary>
        /// <param name="container">The unity container to configure.</param>
        /// <remarks>There is no need to register concrete types such as controllers or API controllers (unless you want to 
        /// change the defaults), as Unity allows resolving a concrete type even if it was not previously registered.</remarks>
        public static void RegisterTypes(IUnityContainer container)
        {
            // NOTE: To load from web.config uncomment the line below. Make sure to add a Microsoft.Practices.Unity.Configuration to the using statements.
            // container.LoadConfiguration();
 
            // TODO: Register your types here
            // container.RegisterType<iproductRepository, ProductRepository>();
        }
    }
}

“Unity bootstrapper for ASP.NET MVC”提供一個 UnityDependencyResolver 類,該類從容器解析控制器。如果你需要為控制器類配置注入,那么你需要手動添加注冊,或者向控制器類注入屬性。

public class ManagementController : Controller
   {
       private readonly ITenantStore tenantStore;
 
       public ManagementController(ITenantStore tenantStore)
       {
           this.tenantStore = tenantStore;
       }
        ……
   }

在 MVC 和 WebAPI 應用程序中使用 Per Request Lifetime Manager

前面的例子展示了如何使用“Unity bootstrapper for ASP.NET MVC”NuGet package 在 MVC 應用程序中處理注冊和解析控制器。該軟件包還包括一個 PerRequestLifetime 管理器。該生命周期管理器使你可以創建一個已注冊類型的實例,其行為就像一個 HTTP 請求范圍內的單件。

如果您正在使用的ASP.NET Web API 項目,有一個“Unity bootstrapper for ASP.NET WebApi”NuGet軟件包,會提供了等同的功能(搜索Unity3中的NuGet包管理器)。你可以在同一個項目中同時使用了“Unity bootstrapper for ASP.NET WebApi”和“Unity bootstrapper for ASP.NET MVC”,它們將共享同一個容器配置類。

用實時信息的解析

在設計時,你不會總知道你需要構造一個依賴的值。在下面例子中顯示,用戶提供一個應用程序必須在運行時必須創建的 blob 容器。例子中,類型解析發生在一個工廠類,它在注冊時確定一個構造函數的參數。下面的代碼示例顯示了這個工廠類。

public class SurveyAnswerContainerFactory : ISurveyAnswerContainerFactory
{
    private readonly IUnityContainer unityContainer;
 
    public SurveyAnswerContainerFactory(IUnityContainer unityContainer)
    {
        Trace.WriteLine(string.Format("Called constructor in SurveyAnswerContainerFactory"), "UNITY");
 
        this.unityContainer = unityContainer;
    }
 
    public IBlobContainer<SurveyAnswer> Create(string tenant, string surveySlug)
    {
        Trace.WriteLine(string.Format("Called Create in SurveyAnswerContainerFactory with tenant={0}, surveySlug={1}", tenant, surveySlug), "UNITY");
 
        var blobContainerName = string.Format(
            CultureInfo.InvariantCulture,
            "surveyanswers-{0}-{1}",
            tenant.ToLowerInvariant(),
            surveySlug.ToLowerInvariant());
        return this.unityContainer.Resolve<IBlobContainer<SurveyAnswer>>(
            new ParameterOverride("blobContainerName", blobContainerName));
    }
}

在本例中,Resolve 方法使用一個參數覆蓋,以對 blobContainerName 參數提供一個值,來構造 Entities-BlobContainer 類,該類已在容器注冊,被注入到 SurveyAnswerContainerFactory 對象。

你前面看到應用程序如何在注入構造函數用 string 參數注冊 IBlobContainer<Survey-Answer> 類型。如果沒有參數覆蓋,這個注冊將失敗,因為容器無法解析 string 類型。

你還可以在 ContainerBootstrapper 類看到參數覆蓋的使用。本例中,參數覆蓋提供 message queues 的創建。當已注冊的 InjectionFactory 執行時,在解析時提供參數覆蓋。

container
              .RegisterType<ISurveyAnswerStore, SurveyAnswerStore>(
                new InjectionFactory((c, t, s) => new SurveyAnswerStore(
                  container.Resolve<ITenantStore>(),
                  container.Resolve<ISurveyAnswerContainerFactory>(),
                  container.Resolve<IMessageQueue<SurveyAnswerStoredMessage>>(new ParameterOverride("queueName", Constants.StandardAnswerQueueName)),
                  container.Resolve<IMessageQueue<SurveyAnswerStoredMessage>>(new ParameterOverride("queueName", Constants.PremiumAnswerQueueName)),
                  container.Resolve<IBlobContainer<List<String>>>())));

參考資料


  • Unity Application Block 1.2 - October 2008,該鏈接的內容已經過期,不再更新,但還是有一定參考價值。關于最新的 Unity 信息在 Unity Application Block site

 

下載 MyDemo and DIwithUnitySample

下載 MyDemo and DIwithUnitySample v2(補充)

下載 Unity3

下載 Unity bootstrapper for ASP.NET MVC

下載 Unity bootstrapper for ASP.NET WebApi

 

Unity xml 配置文件(2)


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲精品v欧美精品v日韩精品| 国产精品久久一| 国产精品人成电影| 日韩禁在线播放| 2020欧美日韩在线视频| 国产成人精品a视频一区www| 伊人精品在线观看| 国产在线拍偷自揄拍精品| 夜夜嗨av色一区二区不卡| 久久久噜噜噜久噜久久| 成人综合国产精品| 最近2019中文字幕一页二页| 亚洲精品不卡在线| 亚洲自拍偷拍第一页| 久久精品久久久久久国产 免费| 91深夜福利视频| 欧美日韩综合视频网址| 欧美性猛交xxxx乱大交蜜桃| www.欧美三级电影.com| 欧美在线免费观看| 久久久久亚洲精品国产| 中文字幕亚洲无线码在线一区| 69av在线视频| 亚洲性视频网址| 欧美性理论片在线观看片免费| 成人免费视频网址| 国产精品第一页在线| 精品在线欧美视频| 国产精品一区二区久久久| 日韩一级黄色av| 91精品国产色综合久久不卡98口| 亚洲精品视频免费| 国产精品9999| 国产欧美一区二区三区久久| 日韩在线观看免费高清| 亚洲人成在线电影| 亚洲精品久久在线| 青青青国产精品一区二区| 亚洲精品aⅴ中文字幕乱码| 久久影视电视剧免费网站清宫辞电视| 中文字幕精品一区久久久久| 另类视频在线观看| 在线观看视频99| 国产91色在线|免| 精品欧美一区二区三区| 川上优av一区二区线观看| 欧美激情精品在线| 国产午夜精品一区理论片飘花| 欧美成人午夜视频| 日韩一区av在线| 黑人巨大精品欧美一区二区三区| 奇米4444一区二区三区| 亚洲精品综合精品自拍| 国产日韩在线看片| 精品国产精品自拍| 久久天天躁狠狠躁夜夜躁| 91久久精品国产91性色| 亚洲第一偷拍网| 日本不卡高字幕在线2019| 久久久国产影院| 亚洲第一区在线| 91精品久久久久久久久久| 亚洲性线免费观看视频成熟| 57pao国产成人免费| 日韩中文字幕免费视频| 人妖精品videosex性欧美| 亚洲韩国欧洲国产日产av| 欧美孕妇与黑人孕交| 国产日韩中文在线| 久久影视电视剧凤归四时歌| 色偷偷噜噜噜亚洲男人| 亚洲午夜精品久久久久久久久久久久| 国产精品一二三视频| 久久精品国产成人| 色偷偷亚洲男人天堂| 91欧美精品成人综合在线观看| 亚洲一区制服诱惑| 在线播放国产一区中文字幕剧情欧美| 国产精品欧美日韩久久| 欧美美女15p| 一区二区三区回区在观看免费视频| 亚洲女人被黑人巨大进入al| 91精品国产综合久久久久久蜜臀| 怡红院精品视频| 国产成人精品免费久久久久| 欧美人与性动交a欧美精品| 国产97在线观看| 久久久噜噜噜久久| 日韩的一区二区| 欧美精品一区三区| www.欧美视频| 日韩av网站大全| 中文字幕久精品免费视频| 亚洲性视频网址| 亚洲天堂免费视频| 亚洲精品黄网在线观看| 欧美在线精品免播放器视频| 国产色视频一区| 日韩中文第一页| 亚洲自拍另类欧美丝袜| 成人黄色av播放免费| 欧美电影免费观看| 久久九九有精品国产23| 亚洲美女自拍视频| 亚洲精品成人久久电影| 国产精品天天狠天天看| 色婷婷av一区二区三区久久| 国产午夜精品久久久| 精品亚洲精品福利线在观看| 日韩免费在线看| 一区二区在线视频播放| 欧美成在线观看| 国产综合久久久久| 成人精品一区二区三区电影黑人| 日本韩国在线不卡| 色妞色视频一区二区三区四区| 亚洲一区二区久久久久久| 国产www精品| 国产亚洲a∨片在线观看| 欧美性视频网站| 国产精品视频一| 亚洲丝袜一区在线| 97精品久久久| 亚洲精品美女免费| 色综合91久久精品中文字幕| 国产精品久久久久久久一区探花| 久久久国产精品一区| 成人激情视频在线观看| 欧美大片第1页| 日韩大片免费观看视频播放| 欧美一级电影免费在线观看| 国产成人精品午夜| 国产大片精品免费永久看nba| 久久人人爽人人爽爽久久| 国产91免费观看| www欧美日韩| 国产成人精品免高潮在线观看| 亚洲男人天堂2024| 成人a视频在线观看| 久久九九全国免费精品观看| 精品网站999www| 77777亚洲午夜久久多人| 国产精品免费一区| 亚洲石原莉奈一区二区在线观看| 亚洲91精品在线观看| 国产欧洲精品视频| 欧美亚洲另类制服自拍| 欧美韩国理论所午夜片917电影| 国产美女久久久| 亚洲女人被黑人巨大进入| 欧美整片在线观看| 亚洲天堂影视av| 欧美黑人xxxⅹ高潮交| 91高潮在线观看| 一本色道久久综合狠狠躁篇的优点| 色综合亚洲精品激情狠狠| 日本aⅴ大伊香蕉精品视频| 日韩欧美999| 国产欧美欧洲在线观看| 欧美日韩国产123| 欧美国产日产韩国视频| 久久精品国产欧美激情| 国产91精品不卡视频| 精品国内自产拍在线观看|