学习.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); } }
以下是代码运行结果: