22.2.6 全局程序集缓存
全局程序集缓存(Global Assembly Cache,GAC)是系统范围内的代码缓存,它由CLR管理,是注册程序集的中央存储库。全局程序集缓存是一个保存了所有共享程序集的系统文件夹。在程序集添加到全局程序集缓存时,全局程序集缓存会对程序集进行完整性检查等操作,以确保程序集没有被篡改。
注意,在.NET Framework 4.0之前,全局程序集缓存位于Windows系统的assembly目录,如果Windows安装在C盘,那么全局程序集缓存的目录就是:
C:\WINDOWS\assembly
而在.NET Framework4.0中,GAC的目录移到了:
C:\WINDOWS\Microsoft.NET\assembly
此目录原本不存在,是在安装.NET Framework 4.0时自动创建的,图22-9是笔者电脑上的全局程序集缓存缓存,系统为虚拟的XP系统。
图 22-9 全局程序集缓存所在的系统目录
GAC下又有几个子目录,在32位系统有GAC_32和GAC_MSIL目录,在64位系统有GAC_32、GAC_64以及GAC_MSIL目录。
❑GAC_32:用于存放指定运行在32位(目标平台为x86)系统上的程序集,这些程序集可能是使用了32位的本地代码。可以直接在32位系统上运行或者使用WOW64技术在64位的系统上运行。
❑GAC_64:用于存放基于x64或者IA64的程序集,这些程序集可能包含64位的本地代码。这个目录在32位系统上不存在。值得注意的是,GAC_64中的程序集是根据系统架构决定的。在x64系统上,该目录中的程序集就必须是基于x64的,基于IA64的程序集就无法被装入,反之亦然。
❑GAC_MSIL:用于存放无特定CPU指定(目标平台为Any CPU)的程序集,这些程序集既可以运行在32位系统也可以运行在64位系统。
只有具有强名称的程序集才可以被安装到全局程序集缓存中。强名称由以下信息组成:❑程序集的文本名称,如:Accessibility;
❑程序集的版本,如:2.0.0.0;
❑程序集的公钥标记,如:b03f5f7f11d50a3a;
❑程序集区域性信息,如:zh_CHS,中国。
在全局程序集缓存中可能存在一个程序集的多个副本,但它们之间不会冲突,因为它们的强名称不同,版本也是强名称的组成部分之一。
可以使用.NET Framework提供的Sn.exe为程序集创建并分配强名称。要使用Sn.exe,可以选用以下两种方法中的一种:
❑开始→所有程序→Microsoft Visual Studio 2010→Visual Studio Tools→Visual Studio命令提示(2010);
❑把Sn.exe所在的目录加入到系统的Path环境变量中去[1],如图22-10所示。此目录的路径与我们在附录A的A.6节介绍的ildasm.exe位于同一个目录。如果你在修改环境变量前已经打开了cmd命令窗口,则需要先关闭再重新打开它。
图 22-10 将Sn.exe文件所在的目录加入环境变量Path中
接下来,我们为ProgrammingCSharp4解决方案下的类库MyLibrary.dll生成并分配强名称,然后将它部署到全局程序集缓存。
(1)打开cmd命令行窗口,或者“Visual Studio命令提示(2010)”。
(2)输入sn -k Key.snk[2],系统提示“密钥对写入到Key.snk”。
(3)回到Visual Studio 2010中,在MyLibrary项目节点上单击右键,从弹出的快捷菜单中选择属性,然后从打开的对话框中单击左侧的“签名”选项卡,并选中“为程序集签名”复选框,然后选择我们生成的密钥文件"Key.snk",保存后重新生成项目,如图22-11所示。
图 22-11 为程序集签名
(4)输入gacutil/i MyLibrary.dll,系统提示“程序集已成功添加到缓存中”。
如果要从全局程序集缓存中移除该程序集,可以输入gacutil/u MyLibrary,系统提示:
程序集:MyLibrary,Version=1.0.0.0,Culture=neutral,PublicKeyToken=8a33aff6b87a74dd,processorArchitecture=MSIL
已卸载:MyLibrary,Version=1.0.0.0,Culture=neutral,PublicKeyToken=8a33aff6b87a74dd,processorArchitecture=MSIL
卸载的程序集数=1
失败次数=0
图22-12是MyLibrary.dll程序集加入到GAC后的截图,因为MyLibrary程序的目标平台设定的是"Any CPU",因此它的程序集被部署到了GAC_MSIL目录。
图 22-12 GAC中的MyLibrary.dll程序集
如同将MyLibrary.dll部署到GAC一样,我们将ProgrammingCSharp4.exe程序集也部署到GAC,而因为ProgrammingCSharp4程序集的目标平台配置成了"x86",因此它被部署到了GAC_32目录,如图22-13所示。
图 22-13 GAC中的ProgrammingCSharp4程序集
由此可以看到,当一个程序集部署到GAC后,首先会根据程序集的目标平台,如果是CPU不限则部署到GACMSIL目录,如果是x86架构则部署到GAC_32目录,如果是X64或IA64则部署到GAC_64目录。接下来的目录结果就比较类似了,首先是以程序集名称作为名称的目录,如MyLibrary。其下是一个或多个子目录,目录的命名规则为:目标框架版本程序集版本区域信息公钥标记,如v4.0_1.0.0.0__8a33aff6b87a74dd。在此目录内才是真正的程序集文件,如MyLibrary.dll。由此可见,即使存在一个程序集的多个副本也是没关系的,目录就把它们分开了,即使程序集的名称和版本号完全一样,但因为公钥标记是不太可能相同的。目录结构如图22-14所示。
图 22-14 GAC目录的结构
[1]在变量值的最后加入一个英文的分号,然后将路径粘贴到分号后。
[2]在变量值的最后加入一个英文的分号,然后将路径粘贴到分号后。