Remoting基本原理及其扩展机制(下)
ContextBoundObject
上下文可以看作应用程序域中一个包含对象和消息接收器的区域。对上下文里的对象的调用会转换成可以被MessageSink(消息接收器)拦截和处理的消息。我们知道要把调用转换成消息,必须通过透明代理这个中介。而且,仅当对象是MarshalByRefObject的子类的实例并被其所在的应用程序域以外的实体调用时,CLR才会为它创建透明代理。这里,我们希望对所有调用使用消息接收器机制,即使那些调用是来自同一个应用程序域中的实体。这个时候我们就需要用到System.ContextBoundObject类了。继承自ContextBoundObject的类的实例同样仅能由透明代理访问。此时,即使在这个类的方法中使用的this引用也是透明代理而不是对这个对象的直接引用。我们会发现ContextBoundObject类继承自MarshalByRefObject,这非常合理,因为它很好地强调了该类的特性——它告诉CLR这个类将会通过透明代理使用。
ContextBoundObject的子类的实例被视为上下文绑定的(context-bound)。没有继承自ContextBoundObject的类的实例则被视为上下文灵活的(context-agile)。上下文绑定的对象永远在其上下文中执行。只要不是远程对象,上下文灵活的对象总是在执行这个调用的上下文中执行。如下图所示:

ContextAttribute
上下文attribute是应用在上下文绑定的类上的.NET attribute。上下文attribute类实现了System.Runtime.Remoting.Contexts.IContextAttribute接口。上下文绑定的类可以应用多个上下文attribute。在这个类的对象创建期间,这个类的每个上下文attribute判断这个对象的创建者所在的上下文是否适用。该操作通过以下方法完成:
public bool IContextAttribute.IsContextOK(Context clientCtx, IConstructionCallMessage ctorMsg)
只要其中一个上下文attribute返回false,CLR就必须创建一个新的上下文来容纳这个新的对象。这样,每个上下文attribute可以在这个新的上下文中注入一个或多个上下文属性。这些注入通过以下方法完成:
public void IContextAttribute.GetPropertiesForNewContext( IConstructionCallMessage ctorMsg)
IContextProperty
上下文属性是实现System.Runtime.Remoting.Contexts.IContextProperty接口的类的实例。每个上下文可以包含多个属性。上下文属性在上下文创建的时候通过上下文attribute注入。一旦每个上下文attribute注入了它的属性,就会为每个属性调用下面的方法。此后就无法在这个上下文中注入另外的属性了:
public void IContextProperty.Freeze( Context ctx )
然后,CLR通过调用下面的方法判断新的上下文能否满足每个属性:
public bool IContextProperty.IsNewContextOK( Context ctx )
每个上下文属性都有一个通过Name属性定义的名称:
public string IContextProperty.Name{ get }
上下文中承载的对象的方法可以通过调用下面的方法访问上下文属性:
IContextProperty Context.GetProperty( string sPropertyName )
这一点很有意思,上下文中的对象通过它们所在的上下文的属性可以共享信息并访问服务。不过,上下文属性的主要作用并不在于此。上下文属性的主要作用在于向相关上下文中的消息接收器区域注入消息接收器(MessageSink)。(消息接收器区域的概念将在后面介绍)
以上注入MessageSink的过程可以用下图概括:
