在这之前,我写过深入介绍MS EnterLib PIAB的文章(参阅《MS Enterprise Library Policy Injection Application Block 深入解析[总结篇]》),也写过WCF与PIAB的集成(参阅:《WCF后续之旅(8):通过WCF Extension 实现与MS Enterprise Library Policy Injection Application Block 的集成》)、WCF与Unity的集成(参阅《WCF后续之旅(7):通过WCF Extension实现和Enterprise Library Unity Container的集成》)以及Unity与PIAB的集成(参阅《Enterprise Library深入解析与灵活应用(1):通过Unity Extension实现和Policy Injection Application Block的集成》、《Enterprise Library深入解析与灵活应用(7):再谈PIAB与Unity之间的集成》)。由于部分实现时基于EnterLib、Unity前一个版本,在新的版本中(EnterLib V4.1与Unity 1.2)中,MS通过Unity对PIAB进行了重新设计与实现,所以我们很有必要重拾着这个话题,谈谈对于新的EnterLib和Unity,如何将PIAB和Unity集成到WCF之中。(Source Code从这里下载)
一、设计原理简述
在EnterLib中,PIAB与Unity的定位分别是轻量级的IoC Container(或者DI Container)与AOP框架。PIAB采用Method Call Interception的机制实现了策略的动态注入,其本身依赖于Interceptable对象的创建;UnityContainer建立在ObjectBuilder2之上,本质上是一个用于对象创建的容器。所以,我们可以通过UnityContainer按照PIAB的要求创建Interceptable对象,就能实现Unity与PIAB之间的集成(参阅《Enterprise Library深入解析与灵活应用(7):再谈PIAB与Unity之间的集成》)。
Unity与WCF之间的集成,本质上就是让WCF使用UnityContainer进行服务实例的创建。而WCF框架内部,服务实例的创建同时一个特殊的对象——InstanceProvider。所以我们可以通过自定义InstanceProvider,并借助UnityContainer进行服务实例的提供,那么就能实现Unity与WCF两者之间的集成。所以,创建基于UnityContainer的InstanceProvider是关键。
二、创建基于UnityContainer的InstanceProvider:UnityInstanceProvider
在WCF框架内部,InstanceProvider用户进行服务实例的提供。所有的InstanceProvider实现了接口System.ServiceModel.Dispatcher.IInstanceProvider,下面是IInstanceProvider的定义。服务实例提供实现在GetInstance中,而ReleaseInstance用于实现对服务实例的释放和资源回收。
1: public interface IInstanceProvider<!--CRLF-->
2: { <!--CRLF-->
4: object GetInstance(InstanceContext instanceContext); <!--CRLF-->
5: object GetInstance(InstanceContext instanceContext, Message message); <!--CRLF-->
6: void ReleaseInstance(InstanceContext instanceContext, object instance);<!--CRLF-->
7: }<!--CRLF-->
我们现在的目的就是创建一个基于Unity的InstanceProvider,借助UnityContainer提供对GetInstance方法的实现,我姑且把这个自定义的InstanceProvider称为UnityInstanceProvider。在正式介绍UnityInstanceProvider的具体实现之前,我先介绍一个辅助类型的定义:UnityTypeMapping。
我们知道,UnityContainer采用动态注册接口或者抽象类于具体类型的匹配关系,使得我们可以利用UnityContaner实现基于接口或者抽象类的方式创建我们希望的具体类的对象。UnityTypeMapping用以描述类型的匹配,其定义如下。Type和Mapto分别表示相应的类型(接口或者抽象类)与被匹配的类型(具体类),Name则表示该Mapping Entry的名称(唯一标识)。
1: public class UnityTypeMapping<!--CRLF-->
2: { <!--CRLF-->
3: public Type Type <!--CRLF-->
4: { get; set; } <!--CRLF-->
5:<!--CRLF-->
6: public Type MapTo <!--CRLF-->
7: { get; set; } <!--CRLF-->
8:<!--CRLF-->
9: public string Name<!--CRLF-->
0: { get; set; } <!--CRLF-->
1: }<!--CRLF-->
Unity可以采用编程和配置的方式实现类型的匹配,在真正的系统开发中,后者是首选。为了实现类型匹配配置(UnityTypeElementCollection)到我们定义的UnityTypeMapping列表(IList<UnityTypeMapping>)之间的转化,我定义了下面一个扩展方法(Extension Method):Copy。
1: public static class Extension<!--CRLF-->
2: { <!--CRLF-->
3: public static IList<UnityTypeMapping> Copy(this UnityTypeElementCollection unityTypeElements)<!--CRLF-->
4: { <!--CRLF-->
5: IList<UnityTypeMapping> mappings = new List<UnityTypeMapping>(); <!--CRLF-->
6: foreach (UnityTypeElement type in unityTypeElements)<!--CRLF-->
7: { <!--CRLF-->
8: mappings.Add(new UnityTypeMapping { Type = type.Type, MapTo = type.MapTo, Name = type.Name }); <!--CRLF-->
9: }<!--CRLF-->
0:<!--CRLF-->
1: return mappings; <!--CRLF-->
2: }<!--CRLF-->
3: }<!--CRLF-->
下面列出了UnityInstanceProvider的具体定义。属性ContractType与Container分别代表服务契约与用于创建服务实例的UnityContainer对象,字段_registeredTypeMapping表示当前UnityContainer相关的类型匹配集合。出于性能的考虑,为了避免UnityContainer的频繁创建和类型匹配关系的频繁解析,我通过两个静态属性|字段来保存它们(Containers和registeredTypeMappings,Key为Container的名称)。在构造函数中接受两个输入参数:contractType与containerName,分别表示服务契约类型与相应UnityContainer的名称。根据containerName判断相应的UnityContainer是否已经创建,如果是,则直接从上述的两个静态变量中提取相应的UnityContainer和类型匹配列表。否则,重新创建UnityContainer,加载相应的配置信息对其进行配置。需要特别指出的是,在对创建的UnityContainer进行初始化的时候,添加了一个特殊的UnityContainerExtension:ExtendedIntercepiton,该UnityContainerExtension用户实现Unity与PIAB的集成,在《Enterprise Library深入解析与灵活应用(7):再谈PIAB与Unity之间的集成》中对ExtendedIntercepiton的实现原理具有详细的介绍。
在GetInstance方法中,我们通过UnityContainer根据服务契约(接口)类新进行具体服务实例的创建。在创建之前,我们需要判断服务契约类型与服务类型之间的类型匹配是否已经注册到UnityContainer中,如果没有,则进行注册,并将类型匹配添加到当前类型匹配列表(_registeredTypeMappings)和全局类型匹配列表(registeredTypeMappings)中。
1: public class UnityInstanceProvider : IInstanceProvider<!--CRLF-->
2: { <!--CRLF-->
3: private static object syncHelper = new object();<!--CRLF-->
4: private static IDictionary<string, IList<UnityTypeMapping>> registeredTypeMappings;<!--CRLF-->
5: public static IDictionary<string, IUnityContainer> Containers<!--CRLF-->
6: { get; private set; } <!--CRLF-->
7:<!--CRLF-->
8: private IList<UnityTypeMapping> _registeredTypeMappings; <!--CRLF-->
9: public Type ContractType <!--CRLF-->
10: { get; private set; } <!--CRLF-->
11: public IUnityContainer Container <!--CRLF-->
12: { get; private set; } <!--CRLF-->
13:<!--CRLF-->
14: static UnityInstanceProvider() <!--CRLF-->
15: { <!--CRLF-->
16: registeredTypeMappings = new Dictionary<string, IList<UnityTypeMapping>>();<!--CRLF-->
17: Containers = new Dictionary<string, IUnityContainer>();<!--CRLF-->
18: }<!--CRLF-->
19:<!--CRLF-->
20: public UnityInstanceProvider(Type contractType, string containerName)<!--CRLF-->
21: { <!--CRLF-->
22: if (contractType == null)<!--CRLF-->
23: { <!--CRLF-->
24: throw new ArgumentNullException("contractType");<!--CRLF-->
25: }<!--CRLF-->
26:<!--CRLF-->
27: this.ContractType = contractType; <!--CRLF-->
28:<!--CRLF-->
29: string key = containerName ?? string.Empty;<!--CRLF-->
30: if (Containers.ContainsKey(key)) <!--CRLF-->
31: { <!--CRLF-->
32: this.Container = Containers[key]; <!--CRLF-->
33: this._registeredTypeMappings = registeredTypeMappings[key]; <!--CRLF-->
34: return; <!--CRLF-->
35: }<!--CRLF-->
36:<!--CRLF-->
37: UnityContainerElement containerElement = this.GetUnitySettings(containerName); <!--CRLF-->
38: IUnityContainer container = new UnityContainer(); <!--CRLF-->
39: if (null != containerElement)<!--CRLF-->
40: { <!--CRLF-->
41: containerElement.Configure(container);<!--CRLF-->
42: }<!--CRLF-->
43: container.AddNewExtension<ExtendedInterception>();<!--CRLF-->
44: PolicyInjectionSettings section = (PolicyInjectionSettings)ConfigurationSourceFactory.Create().GetSection("policyInjection"); <!--CRLF-->
45: if (section != null)<!--CRLF-->
46: { <!--CRLF-->
47: section.ConfigureContainer(this.Container, ConfigurationSourceFactory.Create()); <!--CRLF-->
48: }<!--CRLF-->
49: lock (syncHelper) <!--CRLF-->
50: { <!--CRLF-->
51: if (!Containers.ContainsKey(key)) <!--CRLF-->
52: { <!--CRLF-->
53: Containers[key] = container;<!--CRLF-->
54: registeredTypeMappings[key] = containerElement.Types.Copy();<!--CRLF-->
55: }<!--CRLF-->
56: }<!--CRLF-->
57:<!--CRLF-->
58: this.Container = container; <!--CRLF-->
59: this._registeredTypeMappings = registeredTypeMappings[key]; <!--CRLF-->
60: }<!--CRLF-->
61:<!--CRLF-->
62: #region IInstanceProvider Members <!--CRLF-->
63:<!--CRLF-->
64: public object GetInstance(InstanceContext instanceContext, Message message)<!--CRLF-->
65: { <!--CRLF-->
66: string contractServiceTypeMappingName = string.Empty;<!--CRLF-->
67: var contractServiceTypeMappings = from mapping in this._registeredTypeMappings<!--CRLF-->
68: where mapping.Type == this.ContractType &&<!--CRLF-->
69: mapping.MapTo == instanceContext.Host.Description.ServiceType<!--CRLF-->
70: select mapping;<!--CRLF-->
71: if (contractServiceTypeMappings.Count() == 0) <!--CRLF-->
72: { <!--CRLF-->
73: contractServiceTypeMappingName = Guid.NewGuid().ToString();<!--CRLF-->
74: this.Container.RegisterType(this.ContractType, instanceContext.Host.Description.ServiceType, contractServiceTypeMappingName);<!--CRLF-->
75: this._registeredTypeMappings.Add(new UnityTypeMapping { Type = this.ContractType, MapTo = instanceContext.Host.Description.ServiceType, Name = contractServiceTypeMappingName });<!--CRLF-->
76: }<!--CRLF-->
77: else <!--CRLF-->
78: { <!--CRLF-->
79: contractServiceTypeMappingName = contractServiceTypeMappings.ToArray<UnityTypeMapping>()[0].Name;<!--CRLF-->
80: }<!--CRLF-->
81:<!--CRLF-->
82: return this.Container.Resolve(this.ContractType, contractServiceTypeMappingName);<!--CRLF-->
83: }<!--CRLF-->
84:<!--CRLF-->
本文介绍了如何在WCF中集成Unity和Policy Injection Application Block (PIAB),通过自定义基于Unity的InstanceProvider,实现服务实例的动态创建。
125

被折叠的 条评论
为什么被折叠?



