WCF後續之旅(7):通過WCF Extension實現和Enterprise Library Unity Container的集成
一、Unity Application Block
二、實現基於Unity的IntanceProvider
在本係列的第三部分對Dispachter的介紹,和第四部分對WCF可擴展點的介紹中,我提到了一個重要的對象InstanceProvider, 該對象用於service instance的創建。既然Unity的根本目的是創建對象,我們就可以自定義InstanceProvider,讓Unity來幫助創建service instance,很容易地實現了和Unity的集成。
1: namespace Artech.WCFExtensions
2: {
3: public class UnityInstanceProvider: IInstanceProvider
4: {
5: private Type _contractType;
6: private string _containerName;
7:
8: public UnityInstanceProvider(Type contractType, string containerName)
9: {
10: if (contractType == null)
11: {
12: throw new ArgumentNullException("contractType");
13: }
14:
15: this._containerName = containerName;
16: this._contractType = contractType;
17: }
18:
19: #region IInstanceProvider Members
20:
21: public object GetInstance(InstanceContext instanceContext, Message message)
22: {
23: UnityConfigurationSection unitySection = ConfigurationManager.GetSection("unity") as UnityConfigurationSection;
24: if (unitySection == null)
25: {
26: throw new ConfigurationErrorsException(string.Format(CultureInfo.CurrentCulture, Resources.MissUnityConfiguration));
27: }
28:
29: IUnityContainer container = new UnityContainer();
30: UnityContainerElement containerElement;
31: if (string.IsNullOrEmpty(this._containerName))
32: {
33: containerElement = unitySection.Containers.Default;
34: }
35: else
36: {
37: containerElement = unitySection.Containers[this._containerName];
38: }
39: containerElement.Configure(container);
40: UnityTypeElement[] unityTypeElements = Array.CreateInstance(typeof(UnityTypeElement), containerElement.Types.Count) as UnityTypeElement[];
41: containerElement.Types.CopyTo(unityTypeElements, 0);
42:
43: if (unityTypeElements.Where(element => element.Type == this._contractType).Count() == 0)
44: {
45: container.RegisterType(this._contractType, instanceContext.Host.Description.ServiceType);
46: }
47:
48: return container.Resolve(this._contractType);
49: }
50:
51: public object GetInstance(InstanceContext instanceContext)
52: {
53: return this.GetInstance(instanceContext, null);
54: }
55:
56: public void ReleaseInstance(InstanceContext instanceContext, object instance)
57: {
58: IDisposable disposable = instance as IDisposable;
59: if (disposable != null)
60: {
61: disposable.Dispose();
62: }
63: }
64:
65: #endregion
66: }
67: }
68:
1: private Type _contractType;
2: private string _containerName;
1: UnityConfigurationSection unitySection = ConfigurationManager.GetSection("unity") as UnityConfigurationSection;
2: if (unitySection == null)
3: {
4: throw new ConfigurationErrorsException(string.Format(CultureInfo.CurrentCulture, Resources.MissUnityConfiguration));
5: }
1: IUnityContainer container = new UnityContainer();
2: UnityContainerElement containerElement;
3: if (string.IsNullOrEmpty(this._containerName))
4: {
5: containerElement = unitySection.Containers.Default;
6: }
7: else
8: {
9: containerElement = unitySection.Containers[this._containerName];
10: }
11: containerElement.Configure(container);
12:
1: UnityTypeElement[] unityTypeElements = Array.CreateInstance(typeof(UnityTypeElement), containerElement.Types.Count) as UnityTypeElement[];
2: containerElement.Types.CopyTo(unityTypeElements, 0);
3:
4: if (unityTypeElements.Where(element => element.Type == this._contractType).Count() == 0)
5: {
6: container.RegisterType(this._contractType, instanceContext.Host.Description.ServiceType);
7: }
1: return container.Resolve(this._contractType);
三、創建UnityInstanceProvider對應的Behavior
1: namespace Artech.WCFExtensions
2: {
3: public class UnityBehaviorAttribute:Attribute, IContractBehavior
4: {
5: public string ContainerName
6: { get; set; }
7:
8: #region IContractBehavior Members
9:
10: public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
11: {}
12:
13: public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
14: {}
15:
16: public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
17: {
18: dispatchRuntime.InstanceProvider = new UnityInstanceProvider(contractDescription.ContractType, this.ContainerName);
19: }
20:
21: public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
22: {}
23:
24: #endregion
25: }
26: }
27:
1: namespace Artech.WCFExtensions
2: {
3: public class UnityBehavior: IEndpointBehavior
4: {
5: private string _containerName;
6:
7: public UnityBehavior(string containerName)
8: {
9: this._containerName = containerName;
10: }
11:
12: #region IEndpointBehavior Members
13:
14: public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
15: {}
16:
17: public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
18: {}
19:
20: public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
21: {
22: endpointDispatcher.DispatchRuntime.InstanceProvider = new UnityInstanceProvider(endpoint.Contract.ContractType, this._containerName);
23: }
24:
25: public void Validate(ServiceEndpoint endpoint)
26: {}
27:
28: #endregion
29: }
30: }
31:
1: namespace Artech.WCFExtensions
2: {
3: public class UnityBehaviorElement: BehaviorExtensionElement
4: {
5: [ConfigurationProperty("containerName", IsRequired = false, DefaultValue = "")]
6: public string ContainerName
7: {
8: get
9: {
10: return this["containerName"] as string;
11: }
12: set
13: {
14: this["containerName"] = value;
15: }
16: }
17:
18: public override Type BehaviorType
19: {
20: get
21: {
22: return typeof(UnityBehavior);
23: }
24: }
25:
26: protected override object CreateBehavior()
27: {
28: return new UnityBehavior(this.ContainerName);
29: }
30: }
31: }
32:
四、應用我們的UnityInstanceProvider
1: namespace Artech.Messages.Contract
2: {
3: [ServiceContract]
4: [UnityBehavior(ContainerName ="wcfservice")]
5: public interface IMessage
6: {
7: [OperationContract]
8: string GetMessage(string key);
9: }
10: }
1: namespace Artech.Messages.Service
2: {
3: public class MessageService:IMessage
4: {
5: [Dependency]
6: public IMessageManager MessageManager
7: { get; set; }
8:
9: [InjectionMethod]
10: public void Initialize()
11: {
12: Thread.CurrentThread.CurrentCulture = new CultureInfo("zh-CN");
13: Thread.CurrentThread.CurrentUICulture = new CultureInfo("zh-CN");
14: }
15:
16: #region IMessage Members
17:
18: public string GetMessage(string key)
19: {
20: return this.MessageManager.GetMessage(key, Thread.CurrentThread.CurrentUICulture);
21: }
22:
23: #endregion
24: }
25:
26: public interface IMessageManager
27: {
28: string GetMessage(string key, CultureInfo culture, params object[] parameters);
29: }
30:
31: public class MessageManager : IMessageManager
32: {
33: public ResourceManager ResourceManager
34: { get; set; }
35:
36: public MessageManager()
37: {
38: this.ResourceManager =new ResourceManager("Artech.Messages.Service.Properties.Resources", typeof(Resources).Assembly);
39: }
40:
41: #region IMessageManager Members
42:
43: public string GetMessage(string key, CultureInfo culture, params object[] parameters)
44: {
45: string message = ResourceManager.GetString(key, culture);
46: return string.Format(culture, message, parameters);
47: }
48:
49: #endregion
50: }
51: }
52:
1: [Dependency]
2: public IMessageManager MessageManager
3: { get; set; }
1: [InjectionMethod]
2: public void Initialize()
3: {
4: Thread.CurrentThread.CurrentCulture = new CultureInfo("zh-CN");
5: Thread.CurrentThread.CurrentUICulture = new CultureInfo("zh-CN");
6: }
1: <?xml version="1.0" encoding="utf-8" ?>
2: <configuration>
3: <configSections>
4: <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
5: </configSections>
6:
7: <system.serviceModel>
8: <services>
9: <service name="Artech.Messages.Service.MessageService">
10: <endpoint behaviorConfiguration="" binding="basicHttpBinding"
11: contract="Artech.Messages.Contract.IMessage" />
12: <host>
13: <baseAddresses>
14: <add baseAddress="https://127.0.0.1/messageservice" />
15: </baseAddresses>
16: </host>
17: </service>
18: </services>
19: </system.serviceModel>
20:
21: <unity>
22: <containers>
23: <container name="wcfservice">
24: <types>
25: <type type="Artech.Messages.Service.IMessageManager,Artech.Messages.Service" mapTo="Artech.Messages.Service.MessageManager,Artech.Messages.Service" />
26: </types>
27: </container>
28: </containers>
29: </unity>
30: </configuration>
31:
1: namespace Artech.Messages.Client
2: {
3: class Program
4: {
5: static void Main(string[] args)
6: {
7: using (ChannelFactory<IMessage> channelFactory = new ChannelFactory<IMessage>("messageservice"))
8: {
9: IMessage messageProxy = channelFactory.CreateChannel();
10: Console.WriteLine(messageProxy.GetMessage("HelloWorld"));
11: }
12:
13: Console.Read();
14: }
15: }
16: }
17:
1: <?xml version="1.0" encoding="utf-8" ?>
2: <configuration>
3: <configSections>
4: <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
5: </configSections>
6: <system.serviceModel>
7: <behaviors>
8: <endpointBehaviors>
9: <behavior name="UnityBehavior">
10: <UnityBehaviorExtension containerName="wcfservice" />
11: </behavior>
12: </endpointBehaviors>
13: </behaviors>
14: <extensions>
15: <behaviorExtensions>
16: <add name="UnityBehaviorExtension" type="Artech.WCFExtensions.UnityBehaviorElement, Artech.WCFExtensions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
17: </behaviorExtensions>
18: </extensions>
19: <services>
20: <service name="Artech.Messages.Service.MessageService">
21: <endpoint behaviorConfiguration="UnityBehavior" binding="basicHttpBinding"
22: contract="Artech.Messages.Contract.IMessage" />
23: <host>
24: <baseAddresses>
25: <add baseAddress="https://127.0.0.1/messageservice" />
26: </baseAddresses>
27: </host>
28: </service>
29: </services>
30: </system.serviceModel>
31: <unity>
32: <containers>
33: <container name="wcfservice">
34: <types>
35: <type type="Artech.Messages.Service.IMessageManager,Artech.Messages.Service" mapTo="Artech.Messages.Service.MessageManager,Artech.Messages.Service" />
36: </types>
37: </container>
38: </containers>
39: </unity>
40: </configuration>
41:
WCF後續之旅:
WCF後續之旅(1): WCF是如何通過Binding進行通信的
WCF後續之旅(2): 如何對Channel Layer進行擴展——創建自定義Channel
WCF後續之旅(3): WCF Service Mode Layer 的中樞—Dispatcher
WCF後續之旅(4):WCF Extension Point 概覽
WCF後續之旅(5): 通過WCF Extension實現Localization
WCF後續之旅(6): 通過WCF Extension實現Context信息的傳遞
WCF後續之旅(7):通過WCF Extension實現和Enterprise Library Unity Container的集成
WCF後續之旅(8):通過WCF Extension 實現與MS Enterprise Library Policy Injection Application Block 的集成
WCF後續之旅(9):通過WCF的雙向通信實現Session管理[Part I]
WCF後續之旅(9): 通過WCF雙向通信實現Session管理[Part II]
WCF後續之旅(10): 通過WCF Extension實現以對象池的方式創建Service Instance
WCF後續之旅(11): 關於並發、回調的線程關聯性(Thread Affinity)
WCF後續之旅(12): 線程關聯性(Thread Affinity)對WCF並發訪問的影響
WCF後續之旅(13): 創建一個簡單的WCF SOAP Message攔截、轉發工具[上篇]
WCF後續之旅(13):創建一個簡單的SOAP Message攔截、轉發工具[下篇]
WCF後續之旅(14):TCP端口共享
WCF後續之旅(15): 邏輯地址和物理地址
WCF後續之旅(16): 消息是如何分發到Endpoint的--消息篩選(Message Filter)
WCF後續之旅(17):通過tcpTracer進行消息的路由
微信公眾賬號:大內老A
如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識別二維碼)關注個人公眾號(原來公眾帳號蔣金楠的自媒體將會停用)。
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁麵明顯位置給出原文連接,否則保留追究法律責任的權利。
最後更新:2017-10-30 17:04:55