当前位置:编程学习 > 网站相关 >>

WCF后续之旅(6): 通过WCF Extension实现Context信息的传递

在上一篇文章中,我们讨论了如何通过CallContextInitializer实现Localization的例子,具体的做法是将client端的culture通过SOAP header传到service端,然后通过自定义的CallContextInitializer设置当前方法执行的线程culture。在client端,当前culture信息是通过OperationContext.Current.OutgoingMessageHeaders手工至于SOAP Header中的。实际上,我们可以通过基于WCF的另一个可扩展对象来实现这段逻辑,这个可扩展对象就是MessageInspector。我们今天来讨论MessageInspector应用的另外一个场景:如何通过MessageInspector来传递Context信息。

一、 Ambient Context

在一个多层结构的应用中,我们需要传递一些上下文的信息在各层之间传递,比如:为了进行Audit,需要传递一些当前当前user profile的一些信息。在一些分布式的环境中也可能遇到context信息从client到server的传递。如何实现这种形式的Context信息的传递呢?我们有两种方案:

  • 将Context作为参数传递:将context作为API的一部分,context的提供者在调用context接收者的API的时候显式地设置这些Context信息,context的接收者则直接通过参数将context取出。这虽然能够解决问题,但决不是一个好的解决方案,因为API应该只和具体的业务逻辑有关,而context 一般是与非业务逻辑服务的,比如Audit、Logging等等。此外,将context纳入API作为其一部分,将降低API的稳定性, 比如,今天只需要当前user所在组织的信息,明天可能需求获取当前客户端的IP地址,你的API可以会经常变动,这显然是不允许的。
  • 创建Ambient Context来保存这些context信息:Ambient Context可以在不同的层次之间、甚至是分布式环境中每个节点之间共享或者传递。比如在ASP.NET 应用中,我们通过SessionSate来存储当前Session的信息;通过HttpContext来存储当前Http request的信息。在非Web应用中,我们通过CallContext将context信息存储在TLS(Thread Local Storage)中,当前线程下执行的所有代码都可以访问并设置这些context数据。

二、Application Context

介于上面所述,我创建一个名为Application Context的Ambient Context容器,Application Context实际上是一个dictionary对象,通过key-value pair进行context元素的设置,通过key获取相对应的context元素。Application Context通过CallContext实现,定义很简单

   1: namespace Artech.ContextPropagation
   2: {
   3:     [Serializable]
   4:     public class ApplicationContext : Dictionary<string, object>
   5:     {
   6:         private const string CallContextKey = "__ApplicationContext";
   7:         internal const string ContextHeaderLocalName = "__ApplicationContext";
   8:         internal const string ContextHeaderNamespace = "urn:artech.com";
   9: 
  10:         private void EnsureSerializable(object value)
  11:         {
  12:             if (value == null)
  13:             {
  14:                 throw new ArgumentNullException("value");
  15:             }
  16:             if (!value.GetType().IsSerializable)
  17:             {
  18:                 throw new ArgumentException(string.Format("The argument of the type "{0}" is not serializable!", value.GetType().FullName));
  19:             }
  20:         }
  21: 
  22:         public new object this[string key]
  23:         {
  24:             get{return base[key];}
  25:             set
  26:             {this.EnsureSerializable(value);base[key] = value;}
  27:         }
  28: 
  29:         public int Counter
  30:         {
  31:             get{return (int)this["__Count"];}
  32:             set{this["__Count"] = value;}
  33:         }
  34: 
  35:         public static ApplicationContext Current
  36:         {
  37:             get
  38:             {
  39:                 if (CallContext.GetData(CallContextKey) == null)
  40:                 {
  41:                     CallContext.SetData(CallContextKey, new ApplicationContext());
  42:                 }
  43: 
  44:                 return CallContext.GetData(CallContextKey) as ApplicationContext;
  45:             }
  46:             set
  47:             {
  48:                 CallContext.SetData(CallContextKey, value);
  49:             }
  50:         }
  51:     }
  52: }

由于此Context将会置于SOAP Header中从client端向service端进行传递,我们需要为此message header指定一个local name和namespace,那么在service端,才能通过此local name和namespace获得此message header。同时,在lcoal domain, client或者service,context是通过CallContext进行存取的,CallContext也是一个类似于disctionary的结构,也需要为此定义一个Key:

private const string CallContextKey = "__ApplicationContext"; internal const string ContextHeaderLocalName = "__ApplicationContext";
internal const string ContextHeaderNamespace = "urn:artech.com";

由于ApplicaitonContext直接继承自Dictionary<string,object>,我们可以通过Index进行元素的设置和提取,考虑到context的跨域传播,需要进行序列化,所以重写了Indexer,并添加了可序列化的验证。为了后面演示方面,我们定义一个context item:Counter。

Static类型的Current属性通过CallContext的SetData和GetData方法对当前的ApplicationContext进行设置和提取:

   1: public static ApplicationContext Current
   2: {
   3:     get
  

补充:综合编程 , 其他综合 ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,