欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

学习.NET中的AppDomain

程序员文章站 2022-04-12 11:18:12
什么是AppDomain?AppDomain是一组程序集的逻辑容器,AppDomain是为了提供隔离而设计的。它提供了保护、配置和终止其中每一个应用程序的隔离 AppDomain的功能: 1.一个AppDomain中的对象不能直接访问另一个Appdomain中的对象 一个AppDomain中的代码创 ......

什么是AppDomain?
AppDomain是一组程序集的逻辑容器,AppDomain是为了提供隔离而设计的。它提供了保护、配置和终止其中每一个应用程序的隔离

AppDomain的功能:

1.一个AppDomain中的对象不能直接访问另一个Appdomain中的对象

 一个AppDomain中的代码创建对象后,则这个对象就被创建他的AppDomain所拥有,它的生存期不能超过拥有它的AppDomain,要想访问另一个AppDomain中的对象

只能使用按引用传送或按值传送的语义。这就强制建立了清晰的分隔和边界,这种隔离是AppDomain很容易从进程卸载,而不影响其他运行的AppDomain。

2.AppDomain可以被卸载

CLR不支持从AppDomain中卸载特定的程序集。但可以告诉CLR卸载一个AppDomain,从而卸载AppDomain中包含的所有程序集。

3.AppDomain可以单独保护

AppDomain创建以后会应用一个权限集,它决定了向运行在这个AppDomain中运行代码的最大权限

4.AppDomain可以配置

AppDomain创建后会关联一组配置,这些配置主要影响AppDomain加载程序集的方式。

如何跨AppDomain访问对象?

一个AppDomain要和另一个AppDomain中的类型和对象通信,只能通过良好定义的机制进行。

以下代码演示了如何创建AppDomain、在其中加载程序集并构造程序集定义的类型的实例。演示了以下三种类型在构造时的不同行为:
”按引用封送“(Marshal-By-Reference)类型,“按值封送”类型(Marshal-By-Value)以及完全不能封送的类型

    class Program
    {
        static void Main(string[] args)
        {
            var a = Thread.GetDomain();
            string callingDomianName = Thread.GetDomain().FriendlyName;
            AppDomain a2 = AppDomain.CreateDomain("a2");
            string exeAssembly = Assembly.GetEntryAssembly().FullName;

            //Demo1***使用Marshal-by-reference进行跨域通信***
            Console.WriteLine("{0}#Demo1", Environment.NewLine);
            MarshalByRefType mbrt = null;
            mbrt = (MarshalByRefType)a2.CreateInstanceAndUnwrap(exeAssembly, "ConsoleApplication1.MarshalByRefType");
            //证明得到的是一个代理对象的引用
            Console.WriteLine("是否代理={0}", RemotingServices.IsTransparentProxy(mbrt));
            //看起来像是在MarshalByRefType上调用一个方法,其实不是
            //我们是在代理类型上调用方法,代理使应用切换到真是拥有对象的AppDomian
            //并在真实的对象上调用方法
            mbrt.SomeMethod();

            //卸载新的AppDomain
            AppDomain.Unload(a2);

            try
            {
                //mbrt引用一个有效的代理对象,代理对象引用一个无效的AppDomain
                mbrt.SomeMethod();
                Console.WriteLine("成功调用");
            }
            catch (AppDomainUnloadedException)
            {
                Console.WriteLine("调用失败");
            }

            //***Demo2:使用Marshal-By-Value进行跨AppDomain通信
            Console.WriteLine("{0}#Demo2", Environment.NewLine);

            a2 = AppDomain.CreateDomain("a2");
            mbrt = (MarshalByRefType)a2.CreateInstanceAndUnwrap(exeAssembly, "ConsoleApplication1.MarshalByRefType");
            //对象方法直接返回对象副本,对象按值封送
            MarshalByValType mbvt = mbrt.MethodWithReturn();

            //证明得到的不是对代理对象的引用
            Console.WriteLine("是否代理={0}", RemotingServices.IsTransparentProxy(mbvt));

            //看起来是在MarshalByValType中调用方法,实际上也是如此
            mbvt.ToString();
      
            //卸载新的Appdomain
            AppDomain.Unload(a2);

            try
            {
                //我们是在对象上调用一个方法,不会抛出异常
               mbvt.ToString();
               Console.WriteLine("成功调用");
            }
            catch (AppDomainUnloadedException)
            {
                Console.WriteLine("调用失败");
            }

            //***Demo3:使用不可封送的类型进行跨AppDomain的通信
            Console.WriteLine("{0}#Demo3", Environment.NewLine);
            a2 = AppDomain.CreateDomain("a2");
            mbrt = (MarshalByRefType)a2.CreateInstanceAndUnwrap(exeAssembly, "ConsoleApplication1.MarshalByRefType");
            //返回一个不可封送的对象,抛出异常
            try
            {
                NonMashalbleType nmt = mbrt.MethodArgAndReturn(callingDomianName);
            }
            catch (AppDomainUnloadedException ex)
            {
                Console.WriteLine(ex.Message);
            }
            Console.ReadKey();    
        }
    }

    [Serializable]
    public sealed class MarshalByRefType : MarshalByRefObject
    {
        public MarshalByRefType()
        {
            Console.WriteLine("{0}的构造器在{1}中运行", this.GetType().ToString(), Thread.GetDomain().FriendlyName);
        }

        public void SomeMethod()
        {
            Console.WriteLine("在{0}中执行", Thread.GetDomain().FriendlyName);
        }

        public MarshalByValType MethodWithReturn()
        {
            Console.WriteLine("在{0}中执行", Thread.GetDomain().FriendlyName);
            MarshalByValType t = new MarshalByValType();
            return t;
        }

        public NonMashalbleType MethodArgAndReturn(string callingThreadName)
        {
            Console.WriteLine("来自{0}的调用", callingThreadName);
            NonMashalbleType t = new NonMashalbleType();
            return t;
        }
    }

    [Serializable]
    public sealed class MarshalByValType : Object
    {
        private DateTime m_time = DateTime.Now;

        public MarshalByValType()
        {
            Console.WriteLine("{0}的构造器在{1}中运行,创建于{2:D}", this.GetType().ToString(),
                Thread.GetDomain().FriendlyName, m_time);
        }

        public override string ToString()
        {
            return m_time.ToLongDateString();
        }
    }

    //不能封送的类型
    public sealed class NonMashalbleType
    {
        public NonMashalbleType()
        {
            Console.WriteLine("在{0}中执行", Thread.GetDomain().FriendlyName);
        }
    }

  

 以下是代码运行结果:

学习.NET中的AppDomain