阅读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信息的传递