首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 开源 FAQ 第二书店 博文视点 程序员
频道: 研发 数据库 中间件 信息化 视频 .NET Java 游戏 移动 服务: 人才 外包 培训
    图书品种:235680
       
热门搜索: ASP.NET Ajax Spring Hibernate Java

11.6  共享程序集

现在已经知道如何部署和配置一个私有程序集,接着开始了解共享程序集的作用。和私有程序集一样,共享程序集是类型和(可选)资源的集合。两者的本质区别在于共享程序集的一个副本可供一台机器上的多个应用程序使用。

考虑本书中所有需要添加对System.Windows.Forms.dll的引用的应用程序。查看一下它们的目录,我们将找不到该.NET程序集的私有副本。这是因为System.Windows.Forms.dll被部署为共享程序集。由此可见,如果想要创建一个机器级别(machine-wide)的类库,那么需要把它部署为共享程序集。

在前面提到,一个共享程序集并不部署在使用它的应用程序目录中。相反,共享程序集安装在全局程序集缓存(GAC)。GAC是在Windows目录下名为Assembly的目录(例如,C:\Windows\Assembly),如图11-16所示。

注解   不能把可执行的程序集安装到GAC。只有*.dll文件可以被部署为共享程序集。

11-16  GAC

11.6.1  强名称

在部署程序集到GAC前,必须赋予它一个强名称强名称用于标识给定.NET二进制文件的发行者。“发行者”可以是一个独立程序员,可以是某公司的一个部门,还可以是整个公司。

在一定程度上可以说,强名称在.NET中的作用好比全局唯一标识符(GUID)在COM中的作用。如果学过COM编程,你会想起AppID是标识特定COM应用程序的GUID。与COMGUID值(只是128位的二进制数字)不同,强名称是基于两个密码学上双关的钥(公钥私钥)的,这种机制比起GUID更具唯一性和抗篡改性。

强名称由一组相关数据组成。我们可以使用程序集级别的特性来定义其中的大部分数据:

l    程序集的友好名称(程序集名称减去文件扩展名)。

l    程序集的版本号(使用[AssemblyVersion]特性赋值)。

l    公钥值(使用[AssemblyKeyFile]特性赋值)。

l    用于本地化的可选的区域性标识(使用[AssemblyCulture]特性赋值)。

l    嵌入的数字签名使用基于程序集内容的散列值和私钥值生成。

为了给一个程序集赋予强名称,首先需要使用.NET Framework 2.0 SDK sn.exe工具生成公钥私钥对。sn.exe工具生成一个文件(通常以*.snkStrong Name Key)作为文件扩展名),该文件包含两个不同的但算术上相关的钥:“公”钥和“私”钥。一旦C#编译器确定*.snk文件的位置,它就会在编译过程中使用.publickey标记把公钥值记录到程序集清单里。

另外,C#编译器还会产生一个基于整个程序集内容(CIL代码、元数据等)的散列值。在第3章已经讲过,散列值是对于某一固定输入的独一无二的数值输出。因此,如果更改了.NET程序集的内容(就算只是改变一个字符),编译器将产生完全不同的散列值。散列值结合*.snk文件中的私钥组成数字签名。数字签名将被嵌入到程序集的CLR首部数据中。产生程序集的强名称的整个过程如图11-17所示。

实际的私钥并不在程序集清单中列出,它只用做对程序集内容进行数字签名(结合生成的散列值)。重申一点,使用公钥私钥这个密码学概念,完全是为了确保在.NET领域中,没有任意两个公司、部门或个人拥有相同的标识。程序集被赋予强名称后,就可以安装到GAC中。

注解    强名称同时为程序集提供了一定程度的保护,防止程序集被篡改。因此,.NET建议为每一个程序集都赋予一个强名称,无论该程序集是否被安装到GAC

数字签名

 

程序集
散列码

 

CarLibrary.dll

 

私钥数据

 

数字签名

 

CIL

 

类型元数据

 

清单(带公钥)

 

11-17  编译期间,C#编译器将基于公钥和私钥数据生成数字签名,并把它嵌入到程序集中

11.6.2  CarLibrary.dll赋予强名称

让我们动手为先前创建的CarLibrary.dll赋予强名称(使用Visual Studio 2005打开我们的项目)。首先使用sn.exe工具生成需要的密钥。尽管sn.exe拥有众多命令行参数选项,但现在只需要关心-k标记,它会要求sn.exe工具生成一个包含公钥私钥对的新文件。在硬盘C区创建一个名为MyTestKeyPair的文件夹,打开.NET命令提示窗体转到该目录下,输入以下命令生成MyTestKeyPair.snk文件:

 

sn -k MyTestKeyPair.snk 

 

公钥私钥对生成后,接着需要把MyTestKeyPair.snk文件的位置告诉C#编译器。如果使用Visual Studio 2005创建任何新的C#项目,都会发现初始项目文件(位于解决方案资源管理器的Properties节点)中包含一个AssemblyInfo.cs文件。这个文件包含了大量描述程序集自身的特性。AssemblyKeyFile就是其中一个程序集级别的特性,它用于告诉编译器有效的*.snk文件的位置所在。下面使用一个字符串来定义该位置:

 

[assembly: AssemblyKeyFile(@"C:\MyTestKeyPair\MyTestKeyPair.snk")]

 

由于共享程序集的版本号也作为强名称的一部分,因此为CarLibrary.dll定义一个版本号。在AssemblyInfo.cs文件里,会看到另外一个名为AssemblyVersion的特性。先把它的值设为1.0.*

 

[assembly: AssemblyVersion("1.0.*")]

 

文本框:  
图11-18  强名称程序集在清单中记录了公钥


在本章一开始讲到,.NET版本号由4个部分组成(<major>.<minor>.<build>.<revision>)。如果保持上面的设置,Visual Studio 2005会自动在编译时增加固定版本值(使用了*通配符标记)。当然,我们也可以为程序集设置固定的版本号,只需要使用具体的值代替*通配符就可以了:

 

// 格式:<Major version>.<Minor version>.<Build number>.<Revision>

// 每一部分的有效取值范围都是0~65535

 [assembly: AssemblyVersion("1.0.0.0")]

 

现在,C#编译器已经获取了所有用于生成强名称数据的信息(并没有通过[Assembly Culture]特性设置程序集区域性的值,它将会自动“继承”我们机器的区域性)。编译CarLibrary代码库,然后使用ildasm.exe查看它的清单。会看到.publickey标签记录了公钥的所有信息,而.ver标记则记录了前面通过[AssemblyVersion]特性设置的版本号(如图11-18所示)。

11.6.3  使用Visual Studio 2005为程序集赋予强名称

在部署CarLibrary.dllGAC前,需要指出的是:其实Visual Studio 2005允许我们使用项目的属性页指定*.snk文件的位置(这是目前更提倡的一种做法,在Visual Studio 2005使用[AssemblyKeyFile]特性的话,编译时会产生警告)。选择Signing节点,提供*.snk的路径,选中“Sign the assembly”复选框(如图11-19所示)。

11-19  使用项目属性页指定*.snk文件

11.6.4  GAC中安装和移除共享程序集

最后一步,就是把CarLibrary.dll(现在它已经具有强名称)安装到GAC中。把共享程序集安装到GAC的最简单的方法就是打开Windows资源管理器,把程序集直接拖放到C:\Windows\Assembly中(这对于快速测试非常有好处)。

另外,.NET Framework 2.0 SDK提供了一个名为gacutil.exe的命令行工具,它允许我们检查和修改GAC的内容。表11-1记录了gacutil.exe相关的参数选项(也可以在命令中使用/?标记来查看表11-1)。

11-1  gacutil.exe的各种参数选项

   

   

/i

将强名称程序集安装入GAC

/u

GAC中卸载程序集

/l

GAC中显示程序集(或特定程序集)

 

 

使用以上任何一种方法,把CarLibrary.dll安装到GAC中之后,应该会看到如图11-20的结果。

11-20  具有强名称的共享程序集CarLibrary(版本号1.0.0.0

注解   可以右击程序集图标打开它的属性页。属性页中提供了卸载程序集某一版本的功能(等价于命令行/u标志)。

11.6.5  延迟签名的作用

在构建自己的.NET程序集时,可以使用自己的*.snk文件为它赋予强名称。但是由于公钥私钥天生的敏感性,你的公司或者部门有可能拒绝把主(master*.snk文件给你。这显然是一个问题,因为作为开发人员,把程序集安装到GAC进行测试是家常便饭。为了解决这个问题,.NET提供了一种叫延迟签名delayed signing)的机制。虽然现在对于CarLibrary.dll并不需要这样做,但还是介绍一下它。

延迟签名的机制是这样的:拥有公钥私钥*.snk文件的人使用sn.exe结合-p命令行标志,把公钥从该文件中提取出来,放到另外一个新的文件(testPublicKey.snk)里:

 

sn -p myKey.snk testPublicKey.snk

 

现在,testPublicKey.snk可以分发到每一个开发者手里,他们可以使用它来创建和测试强名称的程序集。为了通知C#编译器当前程序集正在使用延迟签名,开发者必须设置AssemblyDelaySign特性为true,另外还要指定该伪钥文件testPublicKey.snk作为AssemblyKeyFile特性的参数。以下是对项目的AssemblyInfo.cs文件的相关更新:

 

[assembly: AssemblyDelaySign(true)]

[assembly: AssemblyKeyFile(@"C:\MyKey\testPublicKey.snk)]

 

注解   如果使用Visual Studio 2005以上的特性可以在项目的属性页中直接进行更改。

在程序集设置为延迟签名后,需要禁止程序集部署到GAC时进行的自动签名验证过程。因此,使用-vr标志(sn.exe)在当前机器中跳过验证过程:

 

sn.exe -vr MyAssembly.dll

 

当所有测试完成后,该程序集可以发送到拥有公钥私钥*.snk文件的人手中,让他对程序集进行重新签名。此时sn.exe再次发挥作用,使用了-r标志,看以下的命令:

 

sn.exe -r MyAssembly.dll C:\MyKey\myKey.snk

 

最后别忘了把之前禁止的验证过程重新启动,使用-vu标志:

 

sn.exe -vu MyAssembly.dll

 

如果只是构建程序集给自己使用的话,那根本不需要理会延迟签名。但是,如果构建的程序集是给外部组织使用的,那么延迟签名会保证程序集的安全,也让所有相关人员的利益得到最大的保障。

查看所有评论(0)条】

最近评论



正在载入评论列表...
热点评论