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: }
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: }
四、通过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
上一篇:
WCF后续之旅(4):WCF Extension Point 概览
下一篇:
WCF后续之旅(6): 通过WCF Extension实现Context信息的传递
过去一年18个国家的大选活动遭遇黑客攻击
Linq中调用本地方法
《TensorFlow技术解析与实战》——第1章 人工智能概述 1.4什么是TensorFlow
Java并发编程:线程池的使用
《机器人自动化:建模、仿真与控制》一一2.4习题
关于程序员的59条搞笑但却真实无比的编程语录
匹配指定id的HTMLDom元素的正则
Android自定义捕获Application全局异常
[Android] Eclipse Warning: No grammar constraints (DTD or XML schema) detected for the document
开发人员和设计师应该安装的10个Android应用