CLR via C# 读书笔记 6-2 不同AppDomain之间的通信

来源:互联网 发布:大数据与经济发展 编辑:程序博客网 时间:2024/05/20 04:15

原文:http://www.cnblogs.com/PurpleTide/archive/2011/01/06/1927643.html


跨AppDomain通信有两种方式

  1.Marshal By reference : 传递引用

  2.Marshal By Value : 把需要传递的对象 通过序列化反序列化的方式传递过去(值拷贝)

    只有标记为 可序列化 Serializable 的类才能通过 Marshal By Value的方式通信

 

以下代码描述了几种跨域通信的情况

1.AppDomain是CLR的内部行为,windows完全不清楚有AppDomain的存在

2.在新的域中加载Assembly和Type最好用完整限定名(如果直接加载Type, CLR会自动加载Type所在的和所用到的Assembly)

3.默认情况下新建的应用程序域使用和当前域一样的权限设置,如果你需要手动指定权限,那么构造一个PermissionSet参数传给CreateDomain

4.同样的,如果想给应用程序设置不同的配置,构造一个AppDomainSetup传给他(可以设置配置文件,程序路径,影像拷贝什么的..)

5.跨域访问的时候不会发生线程的上下文切换

6.CreateInstanceAndUnwrap 默认调用对象的无参构造函数,当然,有些重载允许你调用有参构造函数

7.只有继承了System.MarshalByRefObject的对象才能以引用方式传递 (这是一个基类....c#又不允许多继承....还是挺麻烦的)

8.只有标记了了Serializable 的对象才能以值方式传递(内部的序列化反序列化) ,这里有比较严重的性能损耗


using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;using System.Reflection;using System.Runtime.Remoting;namespace TestConsole{    public class Program    {        static void Main(string[] args)        {            // 获取一个指向应用程序域的引用            AppDomain adCallingThreadDomain = Thread.GetDomain();            // 每一个应用程序域都会被分配一个名字帮助调试 ,以下代码获取引用程序域的名字            String callingDomainName = adCallingThreadDomain.FriendlyName;            // 获取应用程序域的完整名            String exeAssembly = Assembly.GetEntryAssembly().FullName;            AppDomain ad2 = null;            // ************************************************************************************************************            // 使用Marshal-by-Reference的方式跨域通信            Console.WriteLine("{0}Demo #1", Environment.NewLine);            // 建立一个域,安全和配置均使用当前域的设置            ad2 = AppDomain.CreateDomain("AD #2", null, null);            MarshalByRefType mbrt = null;            // 加载Assembly到新的域,new一个对象并且返回到当前域 (实际上返回的是一个引用代理)             mbrt = (MarshalByRefType)ad2.CreateInstanceAndUnwrap(exeAssembly, "TestConsole.MarshalByRefType");            Console.WriteLine("Type={0}", mbrt.GetType()); // CLR 对GetType做了一些手脚,返回的是被代理数据的真实类型            // 以下代码证明我们获取的是一个代理对象            Console.WriteLine("Is proxy={0}", RemotingServices.IsTransparentProxy(mbrt));            // 我们调用了代理类的SomeMethod() , 代理类跨域访问真正的对象            mbrt.SomeMethod();            // 卸载新建的那个应用程序域            AppDomain.Unload(ad2);            // mbrt refers to a valid proxy object; the proxy object refers to an invalid AppDomain            try            {                // 再次调用代理类的SomeMethod() , 由于域已经被卸载 抛出一个异常                mbrt.SomeMethod();                Console.WriteLine("Successful call.");            }            catch (AppDomainUnloadedException)            {                Console.WriteLine("Failed call.");            }            // ************************************************************************************************************            // 使用Marshal-by-Value 的方式跨域通信            Console.WriteLine("{0}Demo #2", Environment.NewLine);            // 新建域            ad2 = AppDomain.CreateDomain("AD #2", null, null);            // 加载程序集并创建代理类            mbrt = (MarshalByRefType)ad2.CreateInstanceAndUnwrap(exeAssembly, "TestConsole.MarshalByRefType");            // 该方法返回了一个值的拷贝 marshaled by value (not be reference).            MarshalByValType mbvt = mbrt.MethodWithReturn();            // 证明返回值不是一个代理类            Console.WriteLine("Is proxy={0}", RemotingServices.IsTransparentProxy(mbvt));            // 查看返回值是谁创建的            Console.WriteLine("Returned object created " + mbvt.ToString());            // 卸载应用程序域            AppDomain.Unload(ad2);            // 由于是值传递,那么卸载域对函数没有影响 // marshaled by value             try            {                //不会有异常抛出                Console.WriteLine("Returned object created " + mbvt.ToString());                Console.WriteLine("Successful call.");            }            catch (AppDomainUnloadedException)            {                Console.WriteLine("Failed call.");            }            // ************************************************************************************************************            // non-marshalable type 跨域通信            Console.WriteLine("{0}Demo #3", Environment.NewLine);            ad2 = AppDomain.CreateDomain("AD #2", null, null);            mbrt = (MarshalByRefType)ad2.CreateInstanceAndUnwrap(exeAssembly, "TestConsole.MarshalByRefType");            // 没有标记为 Serializable 的类型对象 不能通过marshaled by value 跨域通信            NonMarshalableType nmt = mbrt.MethodArgAndReturn(callingDomainName);        }    }    //即使没有标记为Serializable 也可以通过 marshaled-by-reference 的方式跨域通信    public sealed class MarshalByRefType : MarshalByRefObject    {        public MarshalByRefType()        {            Console.WriteLine("{0} ctor running in {1}",            this.GetType().ToString(), Thread.GetDomain().FriendlyName);        }        public void SomeMethod()        {            Console.WriteLine("Executing in " + Thread.GetDomain().FriendlyName);        }        public MarshalByValType MethodWithReturn()        {            Console.WriteLine("Executing in " + Thread.GetDomain().FriendlyName);            MarshalByValType t = new MarshalByValType();            return t;        }        public NonMarshalableType MethodArgAndReturn(String callingDomainName)        {            // NOTE: callingDomainName is [Serializable]            Console.WriteLine("Calling from ‘{0}’ to ‘{1}’.",            callingDomainName, Thread.GetDomain().FriendlyName);            NonMarshalableType t = new NonMarshalableType();            return t;        }    }    //只有标记为 Serializable 的类型 才能用marshaled by value 的方式跨域通信    [Serializable]    public sealed class MarshalByValType : Object    {        private DateTime m_creationTime = DateTime.Now; // NOTE: DateTime is [Serializable]        public MarshalByValType()        {            Console.WriteLine("{0} ctor running in {1}, Created on {2:D}",            this.GetType().ToString(),            Thread.GetDomain().FriendlyName,            m_creationTime);        }        public override String ToString()        {            return m_creationTime.ToLongDateString();        }    }    // 没有标记为 Serializable 的类型 不能用marshaled by value 的方式跨域通信    // [Serializable]    public sealed class NonMarshalableType : Object    {        public NonMarshalableType()        {            Console.WriteLine("Executing in " + Thread.GetDomain().FriendlyName);        }    }}



代码
原创粉丝点击