通过添加HTTP Header实现上下文数据在WCF的自动传递
多年之前,我写了一篇通过WCF扩展实现上下文信息从客户端自动传递到服务端的文章,其实现机制很简单:将上下文信息存放到SOAP Header进行传递。那么对于非SOAP消息的RESTful服务就不使用了。为了解决这个问题,我们可以将存放上下文信息的地方从SOAP Header替换成HTTP Header。这篇为你消息讲述具体的实现[源代码从这里下载]。
一、 Ambient Context在一个多层结构的应用中,我们需要传递一些上下文的信息在各层之间传递,比如:为了进行Audit,需要传递一些当前当前user profile的一些信息。在一些分布式的环境中也可能遇到context信息从client到server的传递。如何实现这种形式的Context信息的传递呢?我们有两种方案:
二、ApplicationContext介于上面所述,我创建一个名为ApplicationContext的Ambient Context容器,Application Context实际上是一个dictionary对象,通过key-value pair进行context元素的设置,通过key获取相对应的context元素。Application Context通过CallContext实现,定义很简单: 1: public class ApplicationContext: Dictionary<string,string> 3: const string KeyOfApplicationContext = "__ApplicationContext"; 5: { } 7: { 9: { 11: { 14: HttpContext.Current.Session[KeyOfApplicationContext] = new ApplicationContext();
16: return (ApplicationContext)HttpContext.Current.Session[KeyOfApplicationContext];
18:? 20: { 22: } 24: } 26: { 28: } 30:? 32: { 34: set{this["__UserName"] = value;} 36: string Department
38: get { "__Department"); }
40: } 42: { 44: { 46: } 48: }
四、创建ContextReceiver从请求消息中接收上下文 对于服务端,请求消息的接收,以及对当前上下文的设定,实现在一个自定义CallContextInitializer中。该自定义CallContextInitializer起名为ContextReceiver,定义如下。而上下文的获取和设置实现在BeforeInvoke方法中,确保在服务操作在执行的时候当前上下文信息已经存在。在这里通过判断Header名称是否具有”__”前缀确实是否是基于上下文HTTP Header。 void AfterInvoke(object BeforeInvoke(InstanceContext instanceContext,IClientChannel channel,Message message)
foreach (string key in requestProperty.Headers.Keys) 9: if(key.StartsWith("__")) 11: ApplicationContext.Current[key] = requestProperty.Headers[key]; 13: } 15: } class ContextPropagationBehavior: IEndpointBehavior void ApplyClientBehavior(ServiceEndpoint endpoint,System.ServiceModel.Dispatcher.ClientRuntime clientRuntime) 7: } 9: { 11: { 13: } 15: void Validate(ServiceEndpoint endpoint) { }
class ContextPropagationBehaviorElement : BehaviorExtensionElement 4: { 6: } protected override object CreateBehavior() 11: } 1: [ServiceContract] 3: { 5: [WebGet] 7: } 而服务类型很简单。 public ApplicationContext GetContext()
7: } 假设我们采用自我寄宿的方式,我们创建的自定义终结点行为通过如下的配置应用到服务的终结点上。而从配置上我们也可以看到,我们并没有采用基于SOAP的消息交换,而是采用JSON的消息编码方式。 <configuration>
8: webHttp defaultOutgoingResponseFormat="Json" /> 15: Artech.ContextPropagation.Lib,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null" 16: 17: 18: services 19: service ="Service.ContextTestService" 20: endpoint address="http://127.0.0.1/testService" behaviorConfiguration="contextPropagation" 4: 5: 6: 7: contextPropagation 8: 9: 12: client 13: =http://127.0.0.1/testservice 15: ="Service.Interface.IContextTest" ="contextTestService" 16: 17: 18: 19: 20: 21: > 1: ApplicationContext.Current.Username = "Zhan San";
3: using (ChannelFactory<IContextTest> channelFactory = new ChannelFactory<IContextTest>("contextTestService")) 5: IContextTest proxy = channelFactory.CreateChannel(); 7: foreach (var item in context) 9: Console.WriteLine("{0,-20}:{1}",item.Key,item.Value);
11: } 输出结果充分地证明了客户端设置的上下文被成功地传播到了服务端。 2: __Department :IT
七、看看HTTP请求消息的结构为了更加清楚地证实客户端设置的当前上下文是否存在于请求消息中,我们可以通过Fildder查看整个HTTP请求消息(你需要将IP地址127.0.0.1替换成你的主机名)。整个HTTP请求消息如下所示,从中我们可以清楚地看到两个上下文项存在于HTTP Header列表中。 2: Content-Type: application/xml; charset=utf-8
4: __Department: IT 6: Accept-Encoding: gzip,deflate 相关内容
推荐文章
站长推荐
热点阅读
|