.NET程序集的类型和部署方式

  • 一、两种程序集,两种部署

           CLR支持两种程序集:弱命名程序集(weakly named assembly)和强命名程序集(strongly named assembly)。

          弱命名和强命名程序集结构完全相同。也就是说,它们都使用PE文件格式、PE32(+)头、CLR头、元数据、清单表以及IL。两者的区别在于,强命名程序集使用发布者的公钥/私钥进行了签名。这一对密钥允许对程序集进行唯一性的标识、保护和版本控制,并允许程序集部署到用户机器的任何地方,甚至可以部署到Internet上。由于程序集被唯一性地标识,所以当应用程序绑定到强命名程序集时,CLR可以应用一些已知安全的策略。

          程序集可采用两种方式部署:私有或全局。私有部署的程序集是指部署到应用程序基目录或者某个子目录的程序集。弱命名程序集只能以私有方式部署。全局部署的程序集是指部署到一些公认位置的程序集。CLR在查找程序集时,会检查这些位置。强命名程序集既可私有部署,也可全局部署。表1总结了程序集的种类及其部署方式。

    程序集种类

    可以私有部署

    可以全局部署

    弱命名

    强命名

    表1 弱命名和强命名程序集的部署方式

     

  • 二、使用强命名程序集的原因

          要由多个应用程序访问的程序集必须放到公认的目录。另外,检测到对程序集的引用时,CLR必须能自动检查该目录。但现在的问题是:两个(或更多)公司可能生成具有相同文件名的程序集。所以,假如两个程序集都复制到相同的公认目录,最后一个安装的就是"老大",造成正在使用旧程序集的所有应用程序都无法正常工作(这正是Windows "DLL hell"的由来,因为共享DLL全都复制到Systems2目录)。

          只根据文件名来区分程序集明显不够。CLR必须支持对程序集进行唯一性标识的机制。这就是所谓的"强命名程序集"。强命名程序集具有4个重要特性,它们共同对程序集进行唯一性标识:文件名(不计扩展名)、版本号、语言文化和公钥。由于公钥数字很大,所以经常使用从公钥派生的小哈希值,称为公钥标记(public key token)。以下程序集标识字符串(有时称为程序集显示名称)标识了4个完全不同的程序集文件:

    "MyTypes, Version=1.0.8123.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"

    "MyTypes, Version=1.0.8123.0, Culture=en-US, PublicKeyToken=b77a5c561934e089"

    "MyTypes, Version=2.0.1234.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"

    "MyTypes, Version=1.0.8123.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"

     

          任何公司都可以生成MyTypes.dll(或MyTypes.exe)程序集文件,为其分配相同的版本号1.0.8123.0,并将语言文化设为中性。所以,必须有一种方式区分恰好具有相同特性的两个公司的程序集。出于几方面的考虑,Microsoft选择的是标准的公钥/私钥加密技术。具体地说,使用加密技术,不仅能在程序集安装到一台机器上时检查其二进制数据的完整性,还允许每个发布者授予一套不同的权限。所以,一个公司要想唯一性地标识自己的程序集,必须创建一对公钥/私钥。然后,公钥可以和程序集关联。没有任何两家公司有相同的公钥/私钥对。这样一来,两家公司可以创建具有相同名称、版本和语言文化的程序集,同时不会产生任何冲突。

     

  • 三、全局程序集缓存

          由多个应用程序访问的程序集必须放到公认的目录,而且CLR在检测到对该程序集的引用时,必须知道检查该目录。这个公认位置就是全局程序集缓存(Global Assembly Cache,GAC)。GAC的具体位置是一种实现细节,不同版本会有所变化。但是,一般能在以下目录发现它:

    %SystemRoot%\Microsoft.NET\Assemb1y

     

          GAC目录是结构化的:其中包含许多子目录,子目录名称用算法生成。永远不要将程序集文件手动复制到GAC目录;相反,要用工具完成这项任务。工具知道GAC的内部结构,并知道如何生成正确的了目录名。开发和测试时在GAC中安装强命名程序集最常用的工具是GACUtil.exe。

          注意,不能将弱命名程序集放到GAC,因为弱命名程序集没有嵌入公钥和经过私钥签名,无法区分来自不同公组织的同名称、同版本、同语言的程序集。

          为什么要在GAC中"注册"程序集?假定两家公司都生成了名为0urLibrary的程序集,两个程序集都山一个OurLibrary.dll文件构成。这两个文件显然不能存储到同一个目录,否则最后一个安装的会覆盖第一个,造成应用程序被破坏。相反,将程序集安装到GAC,就会在%SystemRoot%\Microsoft.NET\Assembly目录下创建专门的子目录,程序集文件会复制到其中一个子目录。

     

  • 四、在生成的程序集中引用强命名程序集

          你生成的任何程序集都包含对其他强命名程序集的引用,这是因为System.Object在MSCorLib.dll中定义,后者就是强命名程序集。此外,程序集中还可引用由Microsoft、第三方厂商或者你自己公司发布的其他强命名程序集。使用CSC.exe的/reference编译器开关可以指定想引用的程序集文件名。如果文件名是完整路径,CSC.exe会加载指定文件,并根据它的元数据生成程序集。如果指定不含路径的文件名,CSC.exe会尝试在以下目录查找程序集(按所列顺序)。

    1. 工作目录。
    2. CSC.exe所在的目录,目录中还包含CLR的各种DLL文件。
    3. 使用/lib编译器开关指定的任何目录。
    4. 使用LIB环境变量指定的任何目录。

       

  • 五、强命名程序集能放纂改

          用私钥对程序集进行签名,并将公钥和签名嵌入程序集,CLR就可验证程序集未被修改或破坏。程序集安装到GAC时,系统对包含清单的那个文件的内容进行哈希处理,将哈希值与PE文件中嵌入的RSA数字签名进行比较(在用公钥解除了签名之后)。如果两个值完全一致,表明文件内容未被篡改。此外,系统还对程序集的其他文件的内容进行哈希处理,并将哈希值与清单文件的FileDef表中存储的哈希值进行比较。任何一个哈希值不匹配,表明程序集至少有一个文件被篡改,程序集将无法安装到GAC。

          应用程序需要绑定到程序集时,CLR根据被引用程序集的属性(名称、版本、语言文化和公钥)在GAC中定位该程序集。找到被引用程序集,就返回包含它的子目录,并加载清单所在的文件。以这种方式查找程序集,可保证运行时加载的程序集和最初编译时生成的程序集来自同一个发布者,因为进行引用的程序集的AssemblyRef表中的公钥标记与被引用程序集的AssemblyRef表中的公钥匹配。如果被引用程序集不在GAC中,CLR会查找应用程序的基目录,然后查找应用程序配置文件中标注的任何私有路径。然后,如果应用程序由MSI安装,CLR要求MSI定位程序集。如果在任何位置都找不到程序集,那么绑定失败,抛出System.IO.FiIeNotFoundException异常。

          如果强命名程序集文件从GAC之外的位置加载(通过应用程序的基目录,或者通过配置文件中的codeBase元素),CLR会在程序集加载后比较哈希值。也就是说,每次应用程序执行并加载程序集时,都会对文件进行哈希处理,以牺牲性能为代价,保证程序集文件内容没有被篡改。CLR在运行时检测到不匹配的哈希值会抛出System.IO.FileLoadException异常。

     

  • 六、私有部署强命名程序集

          在GAC中安装程序集有几方面的优势。GAC使程序集能被多个应用程序共享,减少了总体物理内存消耗。另外,很容易将程序集的新版本部署到GAC,让所有应用程序都通过发布者策略使用新版本。GAC还实现了对程序集多个版本的并行管理。但GAC通常受到严密保护,只有管理员才能在其中安装程序集。另外,一旦安装到GAC,就违反了"简单复制部署"工这一基本目标。

          虽然强命名程序集能安装到GAC,但绝非必须。事实上,只有由多个应用程序共享的程序集才应部署到GAC。不用共享的应该私有部署。私有部署达成了"简单复制部署"目标,而且能更好地隔离应用程序及其程序集。另外,不要将GAC想象成新的C:\Windows\System32垃圾堆积场。这是因为新版本程序集不会相互覆盖,它们并行安装,每个安装都占用磁盘空间。

          强命名程序集除了部署到GAC或者进行私有部署,还可部署到只有少数应用程序知道的目录。例如,假定强命名程序集由三个应用程序共享。安装时可创建三个目录,每个程序一个目录。再创建第四个目录,专门存储要共享的程序集。每个应用程序安装到自己的目录时都同时安装一个XML配置文件,用codeBase元素指出共享程序集路径。这样在运行时,CLR就知道去那里查找共享程序集。但要注意,这个技术很少使用,也不太推荐使用,因为所有应用程序都不能独立决定何时卸载程序集的文件。

     

  • 七、延迟签名

          大公司(比如Microsoft)会将自己的私钥保存到一个硬件设备中,再将硬件锁进保险库。公司只有少数人才能访问私钥。这项措施可防止私钥泄露,并保证了密钥的完整性。当然,公钥是完全公开的,可以自由分发。

          准备打包自己的强命名程序集时,必须使用受严密保护的私钥对它进行签名。然而,在开发和测试程序集时,访问这些受严密保护的私钥可能有点碍事儿。有鉴于此,.NET Framework提供了对延迟签名(delayed signing)的支持,该技术也称为部分签名(patial signing)。延迟签名允许只用公司的公钥生成程序集,暂时不用私钥。由于使用了公钥,引用了程序集的其他程序集会在它们的AssemblyRef元数据表的记录项中嵌入正确的公钥值。另外,它还使程序集能正确存储到GAC的内部结构中。当然,不用公司的私钥对文件进行签名,便无法实现防篡改保护。这是由于无法对程序集的文件进行哈希处理,无法在文件中嵌入数字签名。然而,失去这种保护不是一个大问题,因为只是在开发阶段才延迟签名。打包和部署程序集肯定会签名。

你可能感兴趣的:(assembly,程序集,assembly)