1. 应用程序域简介
应用程序域是一个操作系统进程中一个或多个应用程序所驻留的分区。同一应用程序域中的对象直接通信。不同应用程序域中的对象的通信方式有两种:一种是跨应用程序域边界传输对象副本,一种是使用代理交换消息。MarshalByRefObject 就是通过使用代理交换消息来跨应用程序域边界进行通信的对象的基类。
2. MarshalByRefObject 跨应用程序域通信
MarshalByRefObject 对象在本地应用程序域的边界内可直接访问。远程应用程序域中的应用程序首次访问 MarshalByRefObject 时,会向该远程应用程序传递代理。对该代理后面的调用将封送回驻留在本地应用程序域中的对象。当跨应用程序域边界使用类型时,类型必须是从 MarshalByRefObject 继承的,而且由于对象的成员在创建它们的应用程序域之外无法使用,所以不得复制对象的状态。
MarshalByRefObject 通过ObjRef封送对象,封送的行为是由真实代理(RemotingProxy)完成。当MarshalByRefObject 通过透明代理传递远程对象时,透明代理将把基于堆栈的方法调用转换为方法调用消息(IMethodCallMessage),转发给真实代理。真实代理封送对象,将方法调用消息转发给远程应用程序域。远程应用程序域监听到方法调用消息后,取出封送好的ObjRef,将其解封(unmarshal)为本地的对象,并获得透明代理,然后将方法调用消息转换为基于堆栈的方法调用对象。
对象是在本地维护的,但是方法可以在远程调用。比如:本地浏览器远程访问一个Web应用程序,浏览器只是发送一个个的请求,Web应用程序提供服务,并返回处理结果。Web应用程序的状态、数据等信息与浏览器没有直接关联。在Remoting中也一样,当本地应用程序获得一个远程对象时,实际上只获得对这个对象的远程引用,虽然可以调用它的方法,但实际上这些操作都是在远程应用程序中完成,即:对象本身并没有被往返传递,传递的 只是传入传出的参数。
3. MarshalByRefObject 示例
using System; using System.Runtime.Remoting; using System.Security.Permissions; public class SetObjectUriForMarshalTest { class TestClass : MarshalByRefObject { } [SecurityPermission(SecurityAction.LinkDemand)] public static void Main() { TestClass obj = new TestClass(); RemotingServices.SetObjectUriForMarshal(obj, "testUri"); RemotingServices.Marshal(obj); Console.WriteLine(RemotingServices.GetObjectUri(obj)); } }