.Net组件程序设计之上下文

在后续篇幅的远程调用的文章里有说到应用程序域,那是大粒度的控制程序集的逻辑存在,那么想对对象的控制又由谁来做主呢? 没错了,就是上下文。CLR把应用程序域更细化了,在应用程序里添置了上下文的概念,上下文是有着一套约束并且负责管理在其中的所有对象的访问的这么一个逻辑的存在。 举个例子吧,虽然有点不恰当但是将就点理解吧。 比如说社会就是应用程序域,我们所住的住宅社区就是上下文的容器,社区的门卫就是上下文的行为,门卫+社区=上下文。而我们就是对象,社区的门卫对于进出社区的陌生人都会问一句:你进来找哪家?找谁?干什么的? 而真正的上下文也是干这个的,实际要忙的多(本篇讲的有点AOP的意思)

图1

上图中只是初步的示例结构,我们接着往下看。

在系统中,我们可以通过Context类的静态属性DefaultContext获取到当前对象所在的上下文,

Context context = Context.DefaultContext;

当然也可以通过Thread类的静态属性CurrentContext来获取到当前的上下文

Context context = Thread.CurrentContext;

图2

(左端红线开头代表线程开始,红线末端代表着线程介绍)

在上下文体系中,是由上下文绑定对象(ContextBoundObject)、上下文属性(IContextAttrbitute)、上下文成员属性(IContextProperty)和消息接收器构成的。

本篇幅只涉及到体系中的前三个知识点,也就是自定义组件服务,究竟是怎么实现的?

在开始讲之前这里要说一下上下文和对象类型,在应用程序域里会有一个默认的上下文,普通的对象可以任何上下文里使用,这样的对象被称为上下文敏捷对象,而有的对象只能在某个特性的上下文中使用,就是继承自ContextBoundObject类型的对象,这样的对象被称为 面向上下文对象。

怎么去理解自定义组件服务呢?

1.上下文成员属性(IContextProperty)

     /// <summary>
     /// 上下文成员属性
     /// </summary>
     public class ContextWriterService:IContextProperty
     {
 
         public void Freeze(System.Runtime.Remoting.Contexts.Context newContext)
         {
             
         }
 
         public bool IsNewContextOK(System.Runtime.Remoting.Contexts.Context newCtx)
         {
             return true;
         }
 
         public string Name
         {
             get { return "ContextService"; }
         }
 
         /// <summary>
         /// 提供的服务
         /// </summary>
         /// <param name="meg"></param>
         public void WriterMessage(string meg)
         {
             Console.WriteLine(meg);
         }
     }

IContextProperty接口的几个成员: Name只读属性,成员属性名称,用作上下文成员属性集合中的关键字,也可以当作是自定义服务的关键字和名称。 Freeze:冻结上下文 IsNewContextOK:判断当前上下文是否满足需求,提供一个放弃创建上下文的机会,如果这个函数返回False的情况下。

IContextProperty类型的对象会存在于上下文的ContextProperties中,当然不是直接添加的,当我们获取到上下文对象的时候,已经上下文对象被冻结了。

2.上下文属性(IContextAttrbitute)

     using System.Runtime.Remoting;
     using System.Runtime.Remoting.Contexts;
     using System.Runtime.Remoting.Activation;
 
 
     [AttributeUsage(AttributeTargets.Class)]
     public class ContextWriterAttribute :Attribute, IContextAttribute
     {
 
         public void GetPropertiesForNewContext(IConstructionCallMessage msg)
         {
             msg.ContextProperties.Add(new ContextWriterService());
         }
 
         public bool IsContextOK(System.Runtime.Remoting.Contexts.Context ctx, IConstructionCallMessage msg)
         {
             ContextWriterService contextService =
                 ctx.GetProperty("ContextService") as ContextWriterService;
             
             if (contextService != null)
             {
                 return true;
             }
             return false;
         }
     }

IContextAttribute接口成员: IsContextOK函数:在运行时调用此方法确定当前上下文是否存在需要的自定义属性,也就是确定当前类型是否在当前上下文中激活。 GetPropertiesForNewContext:是在IsContextOK方法确定了不OK之后调用此方法,这里的IConstructionCallMessage接口类型对象,会被传递到新建的上下文中,并且新建的上下文会根据IConstructionCallMessage类型当中的 ContextProperties来添加为自己的自定义服务,这也是唯一的一个机会可以添加自定义服务到上下文中。 我这里也有一个疑问,望知道的大神给个指点,就是怎么在当前的默认上下文中添加自定义服务?

3.上下文绑定对象(ContextBoundObject)

     [ContextWriter()]
     public class MyContextObject : ContextBoundObject
     {
         public void CallCurrentContextWriterService()
         {
             Context context = Thread.CurrentContext;
             ContextWriterService contextWriterService =
                 context.GetProperty("ContextService") as ContextWriterService;
             if (contextWriterService != null)
             {
                 contextWriterService.WriterMessage("当前上下文ID:"+context.ContextID + "-测试信息");
             }
         }
     }

显而易见MyContextObject是可以获取到ContextWriterService类型,并且拿来使用的。

这些都是上下文坏境中的一部分,当然还有最重要的一部分:消息接收器,本篇幅不作介绍了,会在以后的篇幅中说到。