应用程序域基础

应用程序域基础

们都知道,进程是操作系统进行资源调度和分配基本单位,每个进程实际代表当前应用程序从启动到结束全部过程。对于Windows每一个.exe文件,在运行时都要由一个进程来承载它。与非托管.exe文件不同是,托管.exe文件并没有直接将程序集加载到当前进程当中,而是将程序集加载到应用程序域中,然后将应用程序域加载到进程中。每个进程可以承载多个应用程序域。因此,对于托管程序,每个进程可以承载多个应用程序,这同时也提升应用程序性能,因为进程切换所耗费性能要多于应用程序域切换。

 

 

 

1.1 应用程序域的特点

托管程序为什么要使用应用程序域呢?概括其优点如下:

1.        在一个应用程序中出现错误不会影响其应用程序。

2.        因为类型安全代码不会导致内存错误,所以使用应用程序域可以确保在一个域中运行代码不会影响进程中应用程序。

3.        能够在不停止整个进程情况下停止单个应用程序。

4.        使用应用程序域时,可以卸载在单个应用程序中运行代码。

5.        在一个应用程序中运行代码不能直接访问其应用程序中代码或资源。

强制实施此隔离,公共语言运行库禁止在不同应用程序域中对象之间进行直接调用。要在各域之间传递对象,可以通过复制这些对象,或通过代理访问这些对象。如果复制对象,那么对该对象调用为本地调用。也就是说,调用方和被引用对象位于同一应用程序域中。如果通过代理访问对象,那么对该对象调用为远程调用。在此情况下,调用方和被引用对象位于不同应用程序域中。域间调用所采用远程调用基础结构与两个进程间调用或两台计算机间调用基础结构相同。因此,被引用对象元数据必须对于两个应用程序域均可用,以便用 JIT 正确编译该方法调用。如果调用域对被调用对象元数据没有访问权,则编译可能失败,并引发类型为 System.IO.FileNotFound 异常。

1.        代码行为作用范围由它运行所在应用程序决定。

换言之,应用程序域将提供应用程序版本策略等配置设置、它所访问任意远程程序集位置,以及加载到该域中程序集位置信息。

2.        向代码授予权限可以由代码运行所在应用程序域来控制。

1.2 创建应用程序域

.NET提供相关类和方法来获取当前应用程序域基本信息,也提供创建和配置应用程序域成员。其中,AppDomain 类是应用程序域编程接口,此类包括各种方法,这些方法可以创建和卸载域、创建域中各类型实例以及注册各种通知(如应用程序域卸载)。对于应用程序域卸载,将在第3.1.3节做介绍。

 

代码清单1-1演示如何创建一个应用程序域。

代码清单1-1 创建应用程序域

class Program

    {

 

        static void Main(string[] args)

 

        {

 

           AppDomain myDomain= AppDomain.CreateDomain("xuanhunDomain");//创建名为xuanhunDomain应用程序域

           Console.WriteLine("myDomain name is :{0}",myDomain.FriendlyName);//输出创建程序域名称

           Console.WriteLine("当前程序域名称是:{0}", AppDomain.CurrentDomain.FriendlyName);//输出当前程序域名称

           Console.ReadKey();

 

        }

 

    }

 

输出结果如图1-1所示。

image

1-1 输出应用程序域名称

 

1.3 卸载应用程序域

当完成使用应用程序域时,可使用System.AppDomain.Unload方法将其卸载。Unload 方法会正常关闭指定应用程序域。卸载过程中,没有新线程可以访问该应用程序域,并且会释放该应用程序域特定所有数据结构。加载到应用程序域中所有程序集都会被移除,无法再使用。如果应用程序域中程序集不是特定于域,则程序集数据会保留在内存中,直到整个进程关闭。除关闭整个进程,没有机制可以卸载非特定于域程序集。在某些情况下,卸载应用程序域请求不起作用,并导致CannotUnloadAppDomainException。代码清单1-2在代码清单1-1基础上添加卸载xuanhunDomain程序域语句,并且在卸载后再次尝试输出该应用程序域名称,这将引发CannotUnloadAppDomainException

代码清单1-2 卸载应用程序域

class Program

    {

 

        static void Main(string[] args)

 

        {

 

           AppDomain myDomain= AppDomain.CreateDomain("xuanhunDomain");

 

           Console.WriteLine("myDomain name is :{0}",myDomain.FriendlyName);

 

           Console.WriteLine("当前程序域名称是:{0}", AppDomain.CurrentDomain.FriendlyName);

 

           AppDomain.Unload(myDomain);

 

           try//试图访问被卸载应用程序域

           {

 

               Console.WriteLine("myDomain name is :{0}", myDomain.FriendlyName);

 

           }

 

           catch (CannotUnloadAppDomainExceptione)

 

           {

 

               Console.WriteLine(e.Message);

 

           }

 

           Console.ReadKey();

 

}

 

输出结果如图1-2所示。

image

1-2 卸载应用程序域

 

将程序集加载到应用程序域方法已经在第2章中做介绍,这里就不再重复。下面接着讨论如何获得当前线程应用程序域相关信息,如代码清单1-3所示。

代码清单1-3 获得当前线程应用程序域相关信息

public void GetDomainInfo()

 

        {

 

            ActivationContext tContext = AppDomain.CurrentDomain.ActivationContext;//获取上下文信息

       ApplicationIdentity tIdentity=AppDomain.CurrentDomain.ApplicationIdentity;//获取应用程序标识

         

 

            System.Security.Policy.ApplicationTrust tTrust = AppDomain.CurrentDomain.ApplicationTrust;//获取当前程序信任级别

            string tDirectory = AppDomain.CurrentDomain.BaseDirectory;// 获取基目录,它由程序集冲突解决程序用来探测程序集

            AppDomainManager tDomainManager = AppDomain.CurrentDomain.DomainManager;//获得初始化应用程序域时主机提供域管理器

            string tDynamicDirectory = AppDomain.CurrentDomain.DynamicDirectory;//获取目录,它由程序集冲突解决程序用来探测动态创建程序集

            System.Security.Policy.Evidence tEvidence = AppDomain.CurrentDomain.Evidence;//获取与此应用程序域相关联 Evidence,它用做安全策略输入

            string tFrindlyName = AppDomain.CurrentDomain.FriendlyName;//获取此应用程序域友好名称

            int tId = AppDomain.CurrentDomain.Id;//获得一个整数,该整数唯一标识进程中应用程序域

            bool tIsFullTrusted = AppDomain.CurrentDomain.IsFullyTrusted;//表示当前应用程序域中程序集是否为完全信任级别

            bool tIsHomogenous = AppDomain.CurrentDomain.IsHomogenous;//获取一个值表示是否拥有对加载到当前应用程序域所有程序集权限集合

            long tMSMemorySize = AppDomain.CurrentDomain.MonitoringSurvivedMemorySize;

 

            long tMTAMemorySieze = AppDomain.CurrentDomain.MonitoringTotalAllocatedMemorySize;

 

            TimeSpan tMTPTime = AppDomain.CurrentDomain.MonitoringTotalProcessorTime;

 

            System.Security.PermissionSet tPermissionSet = AppDomain.CurrentDomain.PermissionSet;//获取权限集

            string tRPath = AppDomain.CurrentDomain.RelativeSearchPath;//获取相对于基目录路径,在此程序集冲突解决程序应探测专用程序集

            AppDomainSetup tASetup = AppDomain.CurrentDomain.SetupInformation;//安装信息

            bool tSCopyFiles = AppDomain.CurrentDomain.ShadowCopyFiles;//获取一个指示值,它表明加载到应用程序域中所有程序集是否为影像复制

}

 

在代码清单1-3中,使用AppDomain.CurrentDomain的属性来获取当前应用程序域的实例,可以从中获取当前应用程序域的相关信息,其中.NET 4.0中新增的属性如下:

q  AppDomain.CurrentDomain.MonitoringSurvivedMemorySize。获取上次完全阻止回收后保留下来的、已知由当前应用程序域引用的字节数。

q  AppDomain.CurrentDomain.MonitoringTotalAllocatedMemorySize。获取自从创建应用程序域后由应用程序域进行的所有内存分配的总大小(以字节为单位,不扣除已回收的内存)。

q  AppDomain.CurrentDomain.MonitoringTotalProcessorTime。获取自从进程启动后所有线程在当前应用程序域中执行时所使用的总处理器时间。

q  AppDomain.CurrentDomain.PermissionSet。获取沙箱应用程序域的权限集。

----------------注,本文部分内容改编自《.NET 安全揭秘》

posted @ 2012-06-23 13:30  玄魂  阅读(2828)  评论(4编辑  收藏  举报