-第三章 共享程序集 (1)
2004-12-27
第二章里讲到对程序集的私有部署方式。这章里探讨创建可以被多个应用程序共同访问的程序集,即全局部署程序集(globally deployed assembly)。
3.1 两种程序集、两种部署方式
1、.NET 框架支持两种程序集:强命名程序集(strongly named assembly)和非强命名程序集。
强命名程序集有一个发布者的公钥/私钥对签名,其中的公钥/私钥对唯一地标识了程序集的发布者。利用公钥/私钥对我们可以对程序集进行唯一的标识、安全策略和版本策略。
2、一个程序集有两种部署方式:私有方式和全局方式。
非强命名程序集只能进行私有部署。
全局部署方式将程序集部署在一些CLR确知的地方,当CLR搜索程序集时,它会知道到这些地方去查找。强命名程序集既可以进行私有部署,也可以进行全局部署。
3.2 强命名程序集
1、由于简单地用文件名导致了目前所谓的DLL Hell,强命名程序集就是CLR用来唯一地标识一个程序集的机制。
一个强命名程序集包含四个唯一标识程序集的特征:文件名(无扩展名)、版本号、语言文化标识及一个公有密钥标记(它是公有密钥产生的一个值)。
利用 System.Reflection.AssemblyName 类,可以创建一个程序集,并获取一个程序集名称的各个部分。
2、创建一个强命名程序集首先得有一个密钥,这个密钥可以用强命名实用工具(SN.exe,Strong Name Utility)产生SN.exe的所有命令行开关都是区分大小写的。
例子:
SN –k MyCompany.keys
创建一个名为MyCompany.keys的文件,文件中包含一对以二进制格式存储的公有密钥和私有密钥。
查看公有密钥,现以-p命令开关创建一个只包含公有密钥的文件:
<script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script> name="google_ads_frame" marginwidth="0" marginheight="0" src="http://pagead2.googlesyndication.com/pagead/ads?client=ca-pub-6256594339606954&dt=1209814142090&lmt=1209814142&prev_fmts=250x250_as&format=468x15_0ads_al&output=html&correlator=1209814142000&url=http%3A%2F%2F203.208.37.104%2Fsearch%3Fq%3Dcache%3A2B9hJu4e0BoJ%3Awww.itwen.com%2F07prog%2F02cc%2Fcc20060926%2F62196.html%2B%25E6%259C%25AA%25E8%2583%25BD%25E5%25B0%2586%25E5%25AF%2586%25E9%2592%25A5%25E8%25BD%25AC%25E6%258D%25A2%25E4%25B8%25BA%25E6%25A0%2587%25E8%25AE%25B0%26hl%3Dzh-CN%26ct%3Dclnk%26cd%3D8%26gl%3Dcn%26st_usg%3DALhdy28hrOj02Uhus6dvg2E010r_dNnR7A&color_bg=F0F1F3&color_text=0000ff&color_link=0000ff&color_url=008000&color_border=F0F1F3&ref=http%3A%2F%2Fwww.google.cn%2Fsearch%3Fhl%3Dzh-CN%26q%3D%25E6%259C%25AA%25E8%2583%25BD%25E5%25B0%2586%25E5%25AF%2586%25E9%2592%25A5%25E8%25BD%25AC%25E6%258D%25A2%25E4%25B8%25BA%25E6%25A0%2587%25E8%25AE%25B0%26meta%3D%26aq%3Df&frm=0&cc=139&ga_vid=3734709544452311500.1209814142&ga_sid=1209814142&ga_hid=1210899774&flash=9.0.124.0&u_h=768&u_w=1024&u_ah=738&u_aw=1024&u_cd=32&u_tz=480&u_his=2&u_java=true" frameborder="0" width="468" scrolling="no" height="15" allowtransparency="allowtransparency"> |
SN –p MyCompany.keys MyCompany.PublicKey
然后以 –tp 命令开关查看:
SN –tp MyCompany.PublicKey
公 钥非常大,为了方便开发人员(及终端用户),公有 密 钥 标记(public key)应运而生。公有 密 钥 标记是一个64位的公有 密 钥散列值。SN.exe 的 –tp 命令行开关在输出的末尾显示了和完整公有 密 钥相对应的公有 密 钥 标记。
3、有了公 钥/私 钥对,只需把 System.Reflection.AssemblyKeyFileAttribute 特性的一个实例应用到源代码中就可以创建强命名程序集了:
[assembly:AssemblyKeyFile(“MyCompany.keys”)]
编译器在源代码中遇到该特性时, 将打开其中制定的文件 MyCompany.keys ,用私有 密 钥对程序集进行签名,并 将公有 密 钥嵌入到清单中。只有包含清单的那个PE文件被签名,其他文件时不能被显式签名的。
4、签名过程:
程序集的FileDef清单元数据表(参见2.3的2)包含组成该程序集的所有文件的一个列表,每个文件名称被加入到该清单中时,文件内容被 转换成一个散列值,该散列值 将和文件名一起存入FileDef表中。(默认散列算法时SHA-1,可以用 AL.exe 的 /algid 命令或应用于程序集上的 System.Reflection.AssemblyAlgorithmIdAttribute 定制特性来改变默认的算法);
生成包含清单的PE文件后,该PE文件的整个内容被 转换 为一个散列值(使用的算法总是SHA-1,不能改变),该散列值经由发布者的私有 密 钥签名,生成的RSA数字签名被存储在PE文件的一个保留区域(不包括在散列值的计算中)。最后,PE文件的CLR表头被更新以反映数字签名在文件中的嵌入位置(?在PE文件中的偏移值?)。
另外,发布者的公有 密 钥也被嵌入到PE文件的AssemblyDef清单元数据表中。
5、如果程序集应用到其他程序集的类型和成员,编译器就会在生成的托管模块中嵌入一个AssemblyRef元数据表。该表的每个条目标识的被引用的程序集也有其公有 密 钥信息,因为公有 密 钥过大,为了节省存储空间,这个元数据表存储的只是被引用程序集的公有 密 钥 标记而不是完整的公有 密 钥。
3.3 全局程序集缓存
1、如果一个程序集被多个应用程序访问,那么该程序必须被放在一个CLR已确知的目录下,且CLR在探测到对该程序集的应用时,它必须 能自动到该目录下寻找这个程序集。这个已确知的目录叫做全局程序集缓存(Global Assembly Cache,即GAC),它通常位于下面目录中: