分享
 
 
 

配置文件(2)

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: |||超大  

本文内容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 forasp.netMVC下载 Unity bootstrapper for ASP.NET WebApiUnity 概述UnityapplicationBlock(Unity)是一个轻量级的,可扩展的依赖注入容器,它支持构造函数注入,属性注入和方法调用注入。它为开发人员提供了以下优点:

提供简化的对象创建,特别是层级对象结构和依赖,简化应用程序代码;支持需求抽象;这可以让开发者在运行时或是配置文件指定依赖,简化横切关注点(crosscutting concerns)的管理;通过延迟组件配置到容器,增加了灵活性;具有服务定位器功能;这可以让客户存储或缓存容器。对 ASP.NET Web 应用程序特别有用,开发者可以在 ASP.NET 会话或应用程序中持久容器。环境Windows 7旗舰版 SP1Microsoft Visual Studio Ultimate 2013 Update 4一个真实的例子咋看上去,RegisterTypes 方法有点复杂;下面会详细讨论各种的类型注册;再讨论应用程序如何注册以在运行时需要时解析类型。这个例子也说明,在你应用程序的一个方法内如何完成所有类型的注册。

publicstaticvoidRegisterTypes(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>(newConfiguredRetryPolicyFactory())

.RegisterType<ISurveyAnswerContainerFactory, SurveyAnswerContainerFactory>(newContainerControlledLifetimeManager());

 

// 注册 table 类型

container

.RegisterType<IDataTable<SurveyRow>, DataTable<SurveyRow>>(newInjectionConstructor(storageAccountType, retryPolicyFactoryType, Constants.SurveysTableName))

.RegisterType<IDataTable<QuestionRow>, DataTable<QuestionRow>>(newInjectionConstructor(storageAccountType, retryPolicyFactoryType, Constants.QuestionsTableName));

 

// 注册 message queue 类型, 使用带泛型的 typeof

container

.RegisterType(

typeof(IMessageQueue<>),

typeof(MessageQueue<>),

newInjectionConstructor(storageAccountType, retryPolicyFactoryType,typeof(String)));

 

// 注册 blob 类型

container

.RegisterType<IBlobContainer<List<string>>,

EntitiesBlobContainer<List<string>>>(

newInjectionConstructor(storageAccountType, retryPolicyFactoryType, Constants.SurveyAnswersListsBlobName))

.RegisterType<IBlobContainer<Tenant>,

EntitiesBlobContainer<Tenant>>(

newInjectionConstructor(storageAccountType, retryPolicyFactoryType, Constants.TenantsBlobName))

.RegisterType<IBlobContainer<byte[]>,

FilesBlobContainer>(

newInjectionConstructor(storageAccountType, retryPolicyFactoryType, Constants.LogosBlobName,"image/jpeg"))

.RegisterType<IBlobContainer<SurveyAnswer>,

EntitiesBlobContainer<SurveyAnswer>>(

newInjectionConstructor(storageAccountType, retryPolicyFactoryType,typeof(String)));

 

// 注册 store 类型

container

.RegisterType<ISurveyStore, SurveyStore>()

.RegisterType<ITenantStore, TenantStore>()

.RegisterType<ISurveyAnswerStore, SurveyAnswerStore>(

newInjectionFactory((c, t, s) =>newSurveyAnswerStore(

container.Resolve<ITenantStore>(),

container.Resolve<ISurveyAnswerContainerFactory>(),

container.Resolve<IMessageQueue<SurveyAnswerStoredMessage>>(newParameterOverride("queueName", Constants.StandardAnswerQueueName)),

container.Resolve<IMessageQueue<SurveyAnswerStoredMessage>>(newParameterOverride("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类的具有三个参数的构造函数。

publicDataTable(StorageAccount account, IRetryPolicyFactory retryPolicyFactory,stringtableName)

: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>>(newInjectionConstructor(storageAccountType, retryPolicyFactoryType, Constants.SurveysTableName))

.RegisterType<IDataTable<QuestionRow>, DataTable<QuestionRow>>(newInjectionConstructor(storageAccountType, retryPolicyFactoryType, Constants.QuestionsTableName));

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

container

.RegisterType<IBlobContainer<List<string>>,

EntitiesBlobContainer<List<string>>>(

newInjectionConstructor(storageAccountType, retryPolicyFactoryType, Constants.SurveyAnswersListsBlobName))

.RegisterType<IBlobContainer<Tenant>,

EntitiesBlobContainer<Tenant>>(

newInjectionConstructor(storageAccountType, retryPolicyFactoryType, Constants.TenantsBlobName))

.RegisterType<IBlobContainer<byte[]>,

FilesBlobContainer>(

newInjectionConstructor(storageAccountType, retryPolicyFactoryType, Constants.LogosBlobName,"image/jpeg"))

.RegisterType<IBlobContainer<SurveyAnswer>,

EntitiesBlobContainer<SurveyAnswer>>(

newInjectionConstructor(storageAccountType, retryPolicyFactoryType,typeof(String)));

这里的 blob,跟实际数据库中的 Binary Lob 无关。

除了构造函数注入外,Unity 也支持属性和方法注册。如果你使用属性注入,应该确保属性具有默认值。这个很容易忘记。

注册开放泛型下面代码段使用稍微不同的方法注册MessageQueue类型:它使用RegisterTypes方法的一个重载。

container

.RegisterType(

typeof(IMessageQueue<>),

typeof(MessageQueue<>),

newInjectionConstructor(storageAccountType, retryPolicyFactoryType,typeof(String)));

所谓“开放的泛型”,是泛型的尖括号里没有内容。

该方法使你用任何参数解析MessageQueue类型。下面代码段使用SurveyAnswerStoredMessage类型:

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

参数覆盖本文最开始的代码中,InjectionConstructor构造函数的其中一个参数是typeof(string)。如下所示:

container

.RegisterType(

typeof(IMessageQueue<>),

typeof(MessageQueue<>),

newInjectionConstructor(storageAccountType, retryPolicyFactoryType,typeof(String)));

……

container

.RegisterType<IBlobContainer<SurveyAnswer>,

EntitiesBlobContainer<SurveyAnswer>>(

newInjectionConstructor(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 方法完成初始化工作。如下所示:

staticvoidMain(string[] args)

{

TextWriterTraceListener tr1 =newTextWriterTraceListener(System.Console.Out);

Debug.Listeners.Add(tr1);

 

using(var container =newUnityContainer())

{

Console.WriteLine("# Performing Registrations...");

ContainerBootstrapper.RegisterTypes(container);

Console.WriteLine("Container has {0} Registrations:",

container.Registrations.Count());

foreach(ContainerRegistration itemincontainer.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 配置或直接添加注册。

usingSystem;

usingMicrosoft.Practices.Unity;

usingMicrosoft.Practices.Unity.Configuration;

 

namespaceUnityBootstrapperForMVCDemo.App_Start

{

/// <summary>

/// Specifies the Unity configuration for the main container.

/// </summary>

publicclassUnityConfig

{

#regionUnity Container

privatestaticLazy<IUnityContainer> container =newLazy<IUnityContainer>(() =>

{

var container =newUnityContainer();

RegisterTypes(container);

returncontainer;

});

 

/// <summary>

/// Gets the configured Unity container.

/// </summary>

publicstaticIUnityContainer GetConfiguredContainer()

{

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

publicstaticvoidRegisterTypes(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 类,该类从容器解析控制器。如果你需要为控制器类配置注入,那么你需要手动添加注册,或者向控制器类注入属性。

publicclassManagementController : Controller

{

privatereadonlyITenantStore tenantStore;

 

publicManagementController(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 容器。例子中,类型解析发生在一个工厂类,它在注册时确定一个构造函数的参数。下面的代码示例显示了这个工厂类。

publicclassSurveyAnswerContainerFactory : ISurveyAnswerContainerFactory

{

privatereadonlyIUnityContainer unityContainer;

 

publicSurveyAnswerContainerFactory(IUnityContainer unityContainer)

{

Trace.WriteLine(string.Format("Called constructor in SurveyAnswerContainerFactory"),"UNITY");

 

this.unityContainer = unityContainer;

}

 

publicIBlobContainer<SurveyAnswer> Create(stringtenant,stringsurveySlug)

{

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());

returnthis.unityContainer.Resolve<IBlobContainer<SurveyAnswer>>(

newParameterOverride("blobContainerName", blobContainerName));

}

}

在本例中,Resolve 方法使用一个参数覆盖,以对 blobContainerName 参数提供一个值,来构造 Entities-BlobContainer 类,该类已在容器注册,被注入到 SurveyAnswerContainerFactory 对象。

你前面看到应用程序如何在注入构造函数用 string 参数注册 IBlobContainer<Survey-Answer> 类型。如果没有参数覆盖,这个注册将失败,因为容器无法解析 string 类型。

你还可以在 ContainerBootstrapper 类看到参数覆盖的使用。本例中,参数覆盖提供 message queues 的创建。当已注册的 InjectionFactory 执行时,在解析时提供参数覆盖。

container

.RegisterType<ISurveyAnswerStore, SurveyAnswerStore>(

newInjectionFactory((c, t, s) =>newSurveyAnswerStore(

container.Resolve<ITenantStore>(),

container.Resolve<ISurveyAnswerContainerFactory>(),

container.Resolve<IMessageQueue<SurveyAnswerStoredMessage>>(newParameterOverride("queueName", Constants.StandardAnswerQueueName)),

container.Resolve<IMessageQueue<SurveyAnswerStoredMessage>>(newParameterOverride("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

 

Unityxml配置文件(2)

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有