麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

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

.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)


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 久久精品在线免费观看 | xnxx 日本免费 | 欧美国产精品久久 | 精品一区二区三区免费 | 精品一区二区三区免费看 | 一区二区国产在线 | 久久经典国产视频 | 免费看欧美一级特黄a大片 久久免费视频一区二区三区 | 精品国产乱码久久久久久丨区2区 | 欧美精品国产综合久久 | 色综合久久久久久久久久久 | 曰韩黄色片| 91久久国产 | 国产精品久久久久久影视 | 成人一区二区三区在线 | 91社影院在线观看 | 国产jjizz一区二区三区视频 | 毛片免费观看视频 | 欧美日韩成人一区二区 | 国产一国产精品一级毛片 | 久久国产精品久久久久久电车 | 欧美日韩中文字幕在线视频 | 97zyz成人免费视频 | 黄色视频a级毛片 | 激情小说另类 | 综合国产一区 | 欧美性受xxxx白人性爽 | 亚洲精品a在线观看 | 国产成人aⅴ | 精品成人免费视频 | 九九热视频这里只有精品 | 亚洲日本韩国精品 | 国产亚洲欧美在线视频 | 国内精品国产三级国产a久久 | 国产一级一级片 | 特级a欧美做爰片毛片 | 特级西西444www大精品视频免费看 | 日韩毛片一区二区三区 | 91成人一区 | 国产亚洲精品综合一区91555 | 一本色道久久综合狠狠躁篇适合什么人看 |