閱讀563 返回首頁    go 阿裏雲 go 技術社區[雲棲]


WCF後續之旅(5): 通過WCF Extension實現Localization

一、Message Service

   1: namespace Artech.Messages.Contract
   2: {
   3:     [ServiceContract]
   4:     public interface IMessage
   5:     {
   6:         [OperationContract]
   7:         string GetMessage();
   8:     }
   9: }

wcf_02_05_01

wcf_02_05_02

   1: namespace Artech.Messages.Service
   2: {
   3:     public class MessageService:IMessage
   4:     {
   5:         public string GetMessage()
   6:         {
   7:             return Resources.HelloWorld;
   8:         } 
   9:     }
  10: }

   1: namespace Artech.Messages.Hosting
   2: {
   3:     public class Program
   4:     {
   5:         public static void Main()
   6:         {
   7:             using (ServiceHost host = new ServiceHost(typeof(MessageService)))
   8:             {
   9:                 host.Opened += delegate
  10:                 {
  11:                     Console.WriteLine("Message service has been started up!");
  12:                 }; 
  13:  
  14:                 host.Open(); 
  15:  
  16:                 Console.Read();
  17:             }
  18:         }
  19:     }
  20: } 

   1: <configuration>
   2:     <system.serviceModel>
   3:         <services>
   4:             <service name="Artech.Messages.Service.MessageService">
   5:                 <endpoint binding="basicHttpBinding" contract="Artech.Messages.Contract.IMessage" />
   6:                 <host>
   7:                     <baseAddresses>
   8:                         <add baseAddress="https://127.0.0.1/messageservice" />
   9:                     </baseAddresses>
  10:                 </host>
  11:             </service>
  12:         </services>
  13:     </system.serviceModel>
  14: </configuration> 

   1: <configuration>
   2:     <system.serviceModel>
   3:         <client>
   4:             <endpoint address="https://127.0.0.1/messageservice" binding="basicHttpBinding"
   5:                 contract="Artech.Messages.Contract.IMessage" name="messageservice" />
   6:         </client>
   7:     </system.serviceModel>
   8: </configuration> 

   1: namespace Artech.Messages.Client
   2: {
   3:     class Program
   4:     {
   5:         private const string CultureInfoHeadLocalName = "__CultureInfo";
   6:         private const string CultyreInfoHeaderNamespace = "urn:artech.com"; 
   7:  
   8:         static void Main(string[] args)
   9:         {
  10:             using (ChannelFactory<IMessage> channelFactory = new ChannelFactory<IMessage>("messageservice"))
  11:             {
  12:                 IMessage proxy = channelFactory.CreateChannel();
  13:                 using (OperationContextScope contextScope = new OperationContextScope(proxy as IContextChannel))
  14:                 { 
  15:                     MessageHeader<CultureInfo> header = new MessageHeader<CultureInfo>(Thread.CurrentThread.CurrentUICulture);
  16:                     OperationContext.Current.OutgoingMessageHeaders.Add(header.GetUntypedHeader(CultureInfoHeadLocalName,CultyreInfoHeaderNamespace));
  17:                     Console.WriteLine("The UI culture of current thread is {0}", Thread.CurrentThread.CurrentUICulture);
  18:                     Console.WriteLine(proxy.GetMessage());
  19:                 } 
  20:  
  21:                 Thread.CurrentThread.CurrentUICulture = new CultureInfo("zh-CN");
  22:                 using (OperationContextScope contextScope = new OperationContextScope(proxy as IContextChannel))
  23:                 {
  24:                     MessageHeader<CultureInfo> header = new MessageHeader<CultureInfo>(Thread.CurrentThread.CurrentUICulture);
  25:                     OperationContext.Current.OutgoingMessageHeaders.Add(header.GetUntypedHeader(CultureInfoHeadLocalName, CultyreInfoHeaderNamespace));
  26:                     Console.WriteLine("The UI culture of current thread is {0}", Thread.CurrentThread.CurrentUICulture);
  27:                     Console.WriteLine(proxy.GetMessage());
  28:                 }
  29:             } 
  30:  
  31:             Console.Read();
  32:         }
  33:     }
  34: } 

二、創建CallContextInitializer

   1: public interface ICallContextInitializer
   2: {
   3:     void AfterInvoke(object correlationState);
   4:     object BeforeInvoke(InstanceContext instanceContext, IClientChannel channel, Message message);
   5: } 

   1: namespace Artech.CallContextInitializers
   2: {
   3:     public class CultureSettingCallContextInitializer:ICallContextInitializer
   4:     {
   5:         private const string CultureInfoHeadLocalName = "__CultureInfo";
   6:         private const string CultyreInfoHeaderNamespace = "urn:artech.com"; 
   7:         public void AfterInvoke(object correlationState)
   8:         {
   9:             CultureInfo[] currentCulture = correlationState as CultureInfo[];
  10:             Thread.CurrentThread.CurrentCulture = currentCulture[0];
  11:             Thread.CurrentThread.CurrentUICulture = currentCulture[1];
  12:         } 
  13:  
  14:         public object BeforeInvoke(InstanceContext instanceContext, IClientChannel channel, Message message)
  15:         {
  16:             CultureInfo currentCulture = Thread.CurrentThread.CurrentCulture;
  17:             CultureInfo currentUICulture = Thread.CurrentThread.CurrentUICulture; 
  18:  
  19:             if (message.Headers.FindHeader(CultureInfoHeadLocalName, CultyreInfoHeaderNamespace) > -1)
  20:             {
  21:                 CultureInfo cultureInfo = message.Headers.GetHeader<CultureInfo>(CultureInfoHeadLocalName, CultyreInfoHeaderNamespace);
  22:                 Thread.CurrentThread.CurrentCulture = cultureInfo;
  23:                 Thread.CurrentThread.CurrentUICulture = cultureInfo;
  24:             } 
  25:  
  26:             return new CultureInfo[] { currentCulture, currentUICulture };
  27:         } 
  28:     }
  29: } 

三、通過OperationBehavior應用CallContextInitializer

   1: namespace Artech.CallContextInitializers
   2: {
   3:     public class CultureSettingBehaviorAttribute:Attribute,IOperationBehavior
   4:     {
   5:         public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters){} 
   6:         public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation){} 
   7:         public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
   8:         {
   9:             dispatchOperation.CallContextInitializers.Add(new CultureSettingCallContextInitializer());
  10:         } 
  11:         public void Validate(OperationDescription operationDescription){} 
  12:     }
  13: }

實際上隻有一句有意思的代碼,將CultureSettingCallContextInitializer對象設置到應用了OperationBehavior

   1: dispatchOperation.CallContextInitializers.Add(new CultureSettingCallContextInitializer());

 

   1: {
   2:     [ServiceContract]
   3:     public interface IMessage
   4:     {
   5:         [OperationContract]
   6:         [CultureSettingBehavior]
   7:         string GetMessage();
   8:     }
   9: } 

wcf_02_05_03

四、通過EndpointBehavior運用CallContextInitializer

   1: namespace Artech.CallContextInitializers
   2: {
   3:     public class CultureSettingBehavior: IEndpointBehavior
   4:     {
   5:         public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters){} 
   6:  
   7:         public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime){} 
   8:  
   9:         public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
  10:         {
  11:             foreach (var operation in endpointDispatcher.DispatchRuntime.Operations)
  12:             {
  13:                 operation.CallContextInitializers.Add(new CultureSettingCallContextInitializer());
  14:             }
  15:         } 
  16:  
  17:         public void Validate(ServiceEndpoint endpoint){} 
  18:     }
  19: } 

   1: namespace Artech.CallContextInitializers
   2: {
   3:     public class CultureSettingBehaviorElement: BehaviorExtensionElement
   4:     {
   5:         public override Type BehaviorType
   6:         {
   7:             get
   8:             {
   9:                 return typeof(CultureSettingBehavior);
  10:             }
  11:         } 
  12:  
  13:         protected override object CreateBehavior()
  14:         {
  15:             return new CultureSettingBehavior();
  16:         }
  17:     }
  18: } 

   1: <configuration>
   2:     <system.serviceModel>
   3:         <behaviors>
   4:             <endpointBehaviors>
   5:                 <behavior name="cultureSettingBehavior">
   6:                     <cultureSettingElement />
   7:                 </behavior>
   8:             </endpointBehaviors>
   9:         </behaviors>
  10:         <extensions>
  11:             <behaviorExtensions>
  12:                 <add name="cultureSettingElement" type="Artech.CallContextInitializers.CultureSettingBehaviorElement, Artech.CallContextInitializers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  13:             </behaviorExtensions>
  14:         </extensions>
  15:         <services>
  16:             <service name="Artech.Messages.Service.MessageService">
  17:                 <endpoint behaviorConfiguration="cultureSettingBehavior" binding="basicHttpBinding"
  18:                     contract="Artech.Messages.Contract.IMessage" />
  19:                 <host>
  20:                     <baseAddresses>
  21:                         <add baseAddress="https://127.0.0.1/messageservice" />
  22:                     </baseAddresses>
  23:                 </host>
  24:             </service>
  25:         </services>
  26:     </system.serviceModel>
  27: </configuration> 

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
微博:www.weibo.com/artech
如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識別二維碼)關注個人公眾號(原來公眾帳號蔣金楠的自媒體將會停用)。
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁麵明顯位置給出原文連接,否則保留追究法律責任的權利。
原文鏈接

最後更新:2017-10-30 17:05:01

  上一篇:go  WCF後續之旅(4):WCF Extension Point 概覽
  下一篇:go  WCF後續之旅(6): 通過WCF Extension實現Context信息的傳遞