Enterprise Library深入解析与灵活应用(7):再谈PIAB与Unity之间的集成

网友投稿 634 2022-11-18

Enterprise Library深入解析与灵活应用(7):再谈PIAB与Unity之间的集成

Enterprise Library深入解析与灵活应用(7):再谈PIAB与Unity之间的集成

一、Unity 1.2和EnterLib 4.1如何实现两者的集成

Unity和PIAB两者之间的集成是通过一个特殊的UnityContainerExtension——Microsoft.Practices.Unity.InterceptionExtension.Interception实现的。为了演示Interception的使用,我们创建一个简单的例子。该例子中定义了一服务SyncTimeProvisionService用于实现同步时间的提供,SyncTimeProvisionService实现了接口ISyncTimeProvision。SyncTimeProvisionService本身并不提供具体实现,而是通过另一个组件SyncTimeProvider实现具体的同步时间的返回,SyncTimeProvider实现接口ISyncTimeProvider。

你可以将SyncTimeProvisionService和SyncTimeProvider看成是一个应用中具有依赖关系的两个模块,为了实现两个模块之间的解耦,采用基于接口的依赖是推荐的设计模式。所以,SyncTimeProvisionService并不之间依赖于SyncTimeProvider,而是依赖于SyncTimeProvider的接口ISyncTimeProvider。我们通过Constructor注入实现依赖注入。为了让读者对Unity和PIAB集成的效果具有一个直观的印象,我在SyncTimeProvider 上应用了一个CachingCallHandlerAttribute,如果该CallHandler生效,方法执行的结果将会被缓存,在缓存过期之前,得到的时间将是一样的。相应的代码如下所示:

using System;namespace Artech.InterceptableUnity{ public interface ISyncTimeServiceProvision { DateTime GetCurrentTime(); } public class SyncTimeServiceProvisionService : ISyncTimeServiceProvision { public ISyncTimeProvider SyncTimeProvider { get; private set; } public SyncTimeServiceProvisionService([Dependency]ISyncTimeServiceProvider syncTimeServiceProvider) { this.SyncTimeServiceProvider = syncTimeServiceProvider; } #region ISyncTimeServiceProvision Members public DateTime GetCurrentTime() { return this.SyncTimeProvider.GetCurrentTime(); } #endregion } public interface ISyncTimeProvider { DateTime GetCurrentTime(); } [CachingCallHandler] public class SyncTimeProvider : ISyncTimeProvider { #region ISyncTimeServiceProvider Members public DateTime GetCurrentTime() { return DateTime.Now; } #endregion }}

.csharpcode, .csharpcode pre { font-size: small; color: rgba(0, 0, 0, 1); font-family: consolas, "Courier New", courier, monospace; background-color: rgba(255, 255, 255, 1) }.csharpcode pre { margin: 0 }.csharpcode .rem { color: rgba(0, 128, 0, 1) }.csharpcode .kwrd { color: rgba(0, 0, 255, 1) }.csharpcode .str { color: rgba(0, 96, 128, 1) }.csharpcode .op { color: rgba(0, 0, 192, 1) }.csharpcode .preproc { color: rgba(204, 102, 51, 1) }.csharpcode .asp { background-color: rgba(255, 255, 0, 1) }.csharpcode .html { color: rgba(128, 0, 0, 1) }.csharpcode .attr { color: rgba(255, 0, 0, 1) }.csharpcode .alt { background-color: rgba(244, 244, 244, 1); width: 100%; margin: 0 }.csharpcode .lnum { color: rgba(96, 96, 96, 1) }

那么我们就可以通过下面的方式,利用UnityContainer采用基于接口(ISyncTimeServiceProvision)的方式创建SyncTimeServiceProvisionService ,并调用GetCurrentTime方法:

using System;using System.Threading;using Microsoft.Practices.EnterpriseLibrary.PolicyInjection.CallHandlers;using Microsoft.Practices.Unity;using Microsoft.Practices.Unity.InterceptionExtension;namespace Artech.InterceptableUnity{ class Program { static void Main(string[] args) { IUnityContainer container = new UnityContainer(); container.RegisterType(); container.RegisterType(); container.AddNewExtension(); container.Configure().SetDefaultInterceptorFor(typeof(ISyncTimeServiceProvider), new TransparentProxyInterceptor()); var syncTimeServiceProvision = container.Resolve(); for (int i = 0; i < 5; i++) { Console.WriteLine(syncTimeServiceProvision.GetCurrentTime()); Thread.Sleep(1000); } } }}

.csharpcode, .csharpcode pre { font-size: small; color: rgba(0, 0, 0, 1); font-family: consolas, "Courier New", courier, monospace; background-color: rgba(255, 255, 255, 1) }.csharpcode pre { margin: 0 }.csharpcode .rem { color: rgba(0, 128, 0, 1) }.csharpcode .kwrd { color: rgba(0, 0, 255, 1) }.csharpcode .str { color: rgba(0, 96, 128, 1) }.csharpcode .op { color: rgba(0, 0, 192, 1) }.csharpcode .preproc { color: rgba(204, 102, 51, 1) }.csharpcode .asp { background-color: rgba(255, 255, 0, 1) }.csharpcode .html { color: rgba(128, 0, 0, 1) }.csharpcode .attr { color: rgba(255, 0, 0, 1) }.csharpcode .alt { background-color: rgba(244, 244, 244, 1); width: 100%; margin: 0 }.csharpcode .lnum { color: rgba(96, 96, 96, 1) }

通过下面的输出,我们看出输出的时间都是相同的,从而证实了CachingCallHandlerAttribute的有效性,进而正式了UnityContainer和PIAB的集成:

二、通过自定义UnityContainerExtension的方式实现Unity与PIAB的集成

通过Microsoft.Practices.Unity.InterceptionExtension.Interception对Unity和PIAB两者之间的集成,需要我们借助Interception为每一个需要被劫持(Interception)的类型注册相应的Interceptor(实现接口Microsoft.Practices.Unity.InterceptionExtension.IInterceptor),如下面的代码片断所示。

container.Configure().SetDefaultInterceptorFor(typeof(ISyncTimeServiceProvider), new TransparentProxyInterceptor());

.csharpcode, .csharpcode pre { font-size: small; color: rgba(0, 0, 0, 1); font-family: consolas, "Courier New", courier, monospace; background-color: rgba(255, 255, 255, 1) }.csharpcode pre { margin: 0 }.csharpcode .rem { color: rgba(0, 128, 0, 1) }.csharpcode .kwrd { color: rgba(0, 0, 255, 1) }.csharpcode .str { color: rgba(0, 96, 128, 1) }.csharpcode .op { color: rgba(0, 0, 192, 1) }.csharpcode .preproc { color: rgba(204, 102, 51, 1) }.csharpcode .asp { background-color: rgba(255, 255, 0, 1) }.csharpcode .html { color: rgba(128, 0, 0, 1) }.csharpcode .attr { color: rgba(255, 0, 0, 1) }.csharpcode .alt { background-color: rgba(244, 244, 244, 1); width: 100%; margin: 0 }.csharpcode .lnum { color: rgba(96, 96, 96, 1) }

但是在每多情况下,我们不可能预先确定需要注册哪些对象,或者这样的类型很多,手工注册的方式将不具有可操作性。比如,在一个N-Layer的应用中,上层的对象通过UnityContainer创建下层对象,并且通过PIAB的方式将不同的Crosscutting Concern应用于相应的层次,我们不可能对每一个应用了PAIB CallHandler相关的类型进行Interceptor的注册。

为此,我对Interception进行了扩展,实现了Interceptor的动态注册。Unity采用两种不同的InterceptionStrategy:InstanceInterceptionStrategy和TypeInterceptionStrategy,它们分别采用基于InstanceInterceptor和TypeInterceptor实现方法调用劫持。我继承了InstanceInterceptionStrategy和TypeInterceptionStrategy,将Inteceptor的动态注册定义在PreBuildUp方法中。继承自Interception,在Initialize方法中将两个扩展的InstanceInterceptionStrategy和TypeInterceptionStrategy——ExtendedInstanceInterceptionStrategy和ExtendedTypeInterceptionStrategy添加到UnityContainer的BuildStrategy列表中。在这个扩展的Inteception——ExtendedInterception中,被用于动态注册的Interceptor定义在ExtendedInterception中,默认为TransparentProxyInteceptor。下面是ExtendedInterception、ExtendedInstanceInterceptionStrategy和ExtendedTypeInterceptionStrategy的定义:

ExtendedInterception:

using Microsoft.Practices.Unity.InterceptionExtension;using Microsoft.Practices.Unity.ObjectBuilder;namespace Artech.InterceptableUnity{ public class ExtendedInterception : Interception { public IInterceptor Interceptor { get; internal set; } public ExtendedInterception() { this.Interceptor = new TransparentProxyInterceptor(); } protected override void Initialize() { this.Context.Strategies.Add(new ExtendedInstanceInterceptionStrategy(this), UnityBuildStage.Setup); this.Context.Strategies.Add(new ExtendedTypeInterceptionStrategy(this), UnityBuildStage.PreCreation); this.Context.Container.RegisterInstance(typeof(AttributeDrivenPolicy).AssemblyQualifiedName, new AttributeDrivenPolicy()); } }}

.csharpcode, .csharpcode pre { font-size: small; color: rgba(0, 0, 0, 1); font-family: consolas, "Courier New", courier, monospace; background-color: rgba(255, 255, 255, 1) }.csharpcode pre { margin: 0 }.csharpcode .rem { color: rgba(0, 128, 0, 1) }.csharpcode .kwrd { color: rgba(0, 0, 255, 1) }.csharpcode .str { color: rgba(0, 96, 128, 1) }.csharpcode .op { color: rgba(0, 0, 192, 1) }.csharpcode .preproc { color: rgba(204, 102, 51, 1) }.csharpcode .asp { background-color: rgba(255, 255, 0, 1) }.csharpcode .html { color: rgba(128, 0, 0, 1) }.csharpcode .attr { color: rgba(255, 0, 0, 1) }.csharpcode .alt { background-color: rgba(244, 244, 244, 1); width: 100%; margin: 0 }.csharpcode .lnum { color: rgba(96, 96, 96, 1) }

ExtendedInstanceInterceptionStrategy:

using System;using Microsoft.Practices.ObjectBuilder2;using Microsoft.Practices.Unity;using Microsoft.Practices.Unity.InterceptionExtension;namespace Artech.InterceptableUnity{ public class ExtendedInstanceInterceptionStrategy : InstanceInterceptionStrategy { public ExtendedInterception Interception { get; private set; } public ExtendedInstanceInterceptionStrategy(ExtendedInterception interception) { if (null == interception) { throw new ArgumentNullException("interception"); } this.Interception = interception; } private static IInstanceInterceptionPolicy FindInterceptorPolicy(IBuilderContext context) { Type buildKey = BuildKey.GetType(context.BuildKey); Type type = BuildKey.GetType(context.OriginalBuildKey); IInstanceInterceptionPolicy policy = context.Policies.Get(context.BuildKey, false) ?? context.Policies.Get(buildKey, false); if (policy != null) { return policy; } policy = context.Policies.Get(context.OriginalBuildKey, false) ?? context.Policies.Get(type, false); return policy; } public override void PreBuildUp(IBuilderContext context) { if (BuildKey.GetType(context.BuildKey) == typeof(IUnityContainer)) { return; } IInstanceInterceptionPolicy policy = FindInterceptorPolicy(context); if (null != policy) { if (policy.Interceptor.CanIntercept(BuildKey.GetType(context.BuildKey))) { this.Interception.SetDefaultInterceptorFor(BuildKey.GetType(context.BuildKey), policy.Interceptor); } } else { if (this.Interception.Interceptor.CanIntercept(BuildKey.GetType(context.BuildKey)) && this.Interception.Interceptor is IInstanceInterceptor) { this.Interception.SetDefaultInterceptorFor(BuildKey.GetType(context.BuildKey), (IInstanceInterceptor)this.Interception.Interceptor); } } base.PreBuildUp(context); } }}

.csharpcode, .csharpcode pre { font-size: small; color: rgba(0, 0, 0, 1); font-family: consolas, "Courier New", courier, monospace; background-color: rgba(255, 255, 255, 1) }.csharpcode pre { margin: 0 }.csharpcode .rem { color: rgba(0, 128, 0, 1) }.csharpcode .kwrd { color: rgba(0, 0, 255, 1) }.csharpcode .str { color: rgba(0, 96, 128, 1) }.csharpcode .op { color: rgba(0, 0, 192, 1) }.csharpcode .preproc { color: rgba(204, 102, 51, 1) }.csharpcode .asp { background-color: rgba(255, 255, 0, 1) }.csharpcode .html { color: rgba(128, 0, 0, 1) }.csharpcode .attr { color: rgba(255, 0, 0, 1) }.csharpcode .alt { background-color: rgba(244, 244, 244, 1); width: 100%; margin: 0 }.csharpcode .lnum { color: rgba(96, 96, 96, 1) }

ExtendedTypeInterceptionStrategy:

using System;using Microsoft.Practices.ObjectBuilder2;using Microsoft.Practices.Unity.InterceptionExtension;namespace Artech.InterceptableUnity{ public class ExtendedTypeInterceptionStrategy : TypeInterceptionStrategy { public ExtendedInterception Interception { get; private set; } public ExtendedTypeInterceptionStrategy(ExtendedInterception interception) { if (null == interception) { throw new ArgumentNullException("interception"); } this.Interception = interception; } private static ITypeInterceptionPolicy GetInterceptionPolicy(IBuilderContext context) { ITypeInterceptionPolicy policy = context.Policies.Get(context.BuildKey, false); if (policy == null) { policy = context.Policies.Get(BuildKey.GetType(context.BuildKey), false); } return policy; } public override void PreBuildUp(IBuilderContext context) { var policy = GetInterceptionPolicy(context); if (null != policy) { if (policy.Interceptor.CanIntercept(BuildKey.GetType(context.BuildKey))) { this.Interception.SetInterceptorFor(BuildKey.GetType(context.BuildKey), policy.Interceptor); } } else { if (this.Interception.Interceptor.CanIntercept(BuildKey.GetType(context.BuildKey)) && this.Interception.Interceptor is ITypeInterceptor) { this.Interception.SetDefaultInterceptorFor(BuildKey.GetType(context.BuildKey), (ITypeInterceptor)this.Interception.Interceptor); } } base.PreBuildUp(context); } }}

.csharpcode, .csharpcode pre { font-size: small; color: rgba(0, 0, 0, 1); font-family: consolas, "Courier New", courier, monospace; background-color: rgba(255, 255, 255, 1) }.csharpcode pre { margin: 0 }.csharpcode .rem { color: rgba(0, 128, 0, 1) }.csharpcode .kwrd { color: rgba(0, 0, 255, 1) }.csharpcode .str { color: rgba(0, 96, 128, 1) }.csharpcode .op { color: rgba(0, 0, 192, 1) }.csharpcode .preproc { color: rgba(204, 102, 51, 1) }.csharpcode .asp { background-color: rgba(255, 255, 0, 1) }.csharpcode .html { color: rgba(128, 0, 0, 1) }.csharpcode .attr { color: rgba(255, 0, 0, 1) }.csharpcode .alt { background-color: rgba(244, 244, 244, 1); width: 100%; margin: 0 }.csharpcode .lnum { color: rgba(96, 96, 96, 1) }

using System;using System.Threading;using Microsoft.Practices.EnterpriseLibrary.PolicyInjection.CallHandlers;using Microsoft.Practices.Unity;using Microsoft.Practices.Unity.InterceptionExtension;namespace Artech.InterceptableUnity{ class Program { static void Main(string[] args) { IUnityContainer container = new UnityContainer(); container.RegisterType(); container.RegisterType(); ExtendedInterception interception = new ExtendedInterception(); interception.Interceptor = new TransparentProxyInterceptor(); container.AddExtension(interception); var syncTimeServiceProvision = container.Resolve(); for (int i = 0; i < 5; i++) { Console.WriteLine(syncTimeServiceProvision.GetCurrentTime()); Thread.Sleep(1000); } } }

.csharpcode, .csharpcode pre { font-size: small; color: rgba(0, 0, 0, 1); font-family: consolas, "Courier New", courier, monospace; background-color: rgba(255, 255, 255, 1) }.csharpcode pre { margin: 0 }.csharpcode .rem { color: rgba(0, 128, 0, 1) }.csharpcode .kwrd { color: rgba(0, 0, 255, 1) }.csharpcode .str { color: rgba(0, 96, 128, 1) }.csharpcode .op { color: rgba(0, 0, 192, 1) }.csharpcode .preproc { color: rgba(204, 102, 51, 1) }.csharpcode .asp { background-color: rgba(255, 255, 0, 1) }.csharpcode .html { color: rgba(128, 0, 0, 1) }.csharpcode .attr { color: rgba(255, 0, 0, 1) }.csharpcode .alt { background-color: rgba(244, 244, 244, 1); width: 100%; margin: 0 }.csharpcode .lnum { color: rgba(96, 96, 96, 1) }

三、通过配置的方式应用ExtendedInterception

为了通过配置的方式应用ExtendedInterception,我们需要为之定义相应的配置类型,一个继承自Microsoft.Practices.Unity.Configuration.UnityContainerExtensionConfigurationElement得类型。为此,我定义了下面一个ExtendedInterceptionElement类型,配置属性为默认的Inteceptor的类型。

using System;using System.Configuration;using Microsoft.Practices.Unity;using Microsoft.Practices.Unity.Configuration;using Microsoft.Practices.Unity.InterceptionExtension;namespace Artech.InterceptableUnity{ public class ExtendedInterceptionElement : UnityContainerExtensionConfigurationElement { [ConfigurationProperty("interceptor", IsRequired = false, DefaultValue = "")] public string Interceptor { get { return (string)this["interceptor"]; } } public override void Configure(IUnityContainer container) { base.Configure(container); ExtendedInterception interception = new ExtendedInterception(); if (!string.IsNullOrEmpty(this.Interceptor)) { var type = System.Type.GetType(this.Interceptor); if (null == type) { throw new ConfigurationErrorsException(string.Format("The {0} is not a valid Interceptor.", this.Interceptor)); } if (!typeof(IInterceptor).IsAssignableFrom(type)) { throw new ConfigurationErrorsException(string.Format("The {0} is not a valid Interceptor.", this.Interceptor)); } interception.Interceptor = (IInterceptor)Activator.CreateInstance(type); } container.AddExtension(interception); } }}

.csharpcode, .csharpcode pre { font-size: small; color: rgba(0, 0, 0, 1); font-family: consolas, "Courier New", courier, monospace; background-color: rgba(255, 255, 255, 1) }.csharpcode pre { margin: 0 }.csharpcode .rem { color: rgba(0, 128, 0, 1) }.csharpcode .kwrd { color: rgba(0, 0, 255, 1) }.csharpcode .str { color: rgba(0, 96, 128, 1) }.csharpcode .op { color: rgba(0, 0, 192, 1) }.csharpcode .preproc { color: rgba(204, 102, 51, 1) }.csharpcode .asp { background-color: rgba(255, 255, 0, 1) }.csharpcode .html { color: rgba(128, 0, 0, 1) }.csharpcode .attr { color: rgba(255, 0, 0, 1) }.csharpcode .alt { background-color: rgba(244, 244, 244, 1); width: 100%; margin: 0 }.csharpcode .lnum { color: rgba(96, 96, 96, 1) }

那么对于上面的例子,我么可以将Type Mapping和ExtendedInterception扩展定义在如下一个配置文件中:

.csharpcode, .csharpcode pre { font-size: small; color: rgba(0, 0, 0, 1); font-family: consolas, "Courier New", courier, monospace; background-color: rgba(255, 255, 255, 1) }.csharpcode pre { margin: 0 }.csharpcode .rem { color: rgba(0, 128, 0, 1) }.csharpcode .kwrd { color: rgba(0, 0, 255, 1) }.csharpcode .str { color: rgba(0, 96, 128, 1) }.csharpcode .op { color: rgba(0, 0, 192, 1) }.csharpcode .preproc { color: rgba(204, 102, 51, 1) }.csharpcode .asp { background-color: rgba(255, 255, 0, 1) }.csharpcode .html { color: rgba(128, 0, 0, 1) }.csharpcode .attr { color: rgba(255, 0, 0, 1) }.csharpcode .alt { background-color: rgba(244, 244, 244, 1); width: 100%; margin: 0 }.csharpcode .lnum { color: rgba(96, 96, 96, 1) }

那么我们的代码将会变得异常简洁:

using System;using System.Threading;using Microsoft.Practices.EnterpriseLibrary.PolicyInjection.CallHandlers;using Microsoft.Practices.Unity;using Microsoft.Practices.Unity.InterceptionExtension;using Microsoft.Practices.Unity.Configuration;using System.Configuration;namespace Artech.InterceptableUnity{ class Program { static void Main(string[] args) { IUnityContainer container = new UnityContainer(); UnityConfigurationSection configuration = (UnityConfigurationSection)ConfigurationManager.GetSection("unity") ; configuration.Containers.Default.Configure(container); var syncTimeServiceProvision = container.Resolve(); for (int i = 0; i < 5; i++) { Console.WriteLine(syncTimeServiceProvision.GetCurrentTime()); Thread.Sleep(1000); } } }}

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:开阔了眼界
下一篇:冯况 | 删除文件显示【需要来自system的权限】
相关文章

 发表评论

暂时没有评论,来抢沙发吧~