【CLR】程序集查找与GAC
文章目录
- 1. 各种各样的版本号
- 2. 程序集的查找
- 2.1 CLR查找程序集顺序
- 3. 强命名程序集与弱命名程序集
- 3.1 Dll hell问题
- 3.1.1 对弱程序集签名,使其变成强程序集
- 3.1.2 全局程序集缓存GAC
- 3.1.3 在你的项目中如何引用强程序集?
1. 各种各样的版本号
如图:
- AssemblyVersion程序集版本号:存储在AssemblyDef清单元数据表中,虽然在文件属性面板中不显示,但是这个版本号对于CLR来说很重要,绑定强明明程序集时会用到这个,它唯一地标识了程序集。当A程序集引用了B程序集时,会将B程序集的AssemblyVersion嵌入到自己的AssemblyDef清单中,这样当CLR加载B的时候,就能准确的知道是程序集B的哪个版本。
- AssemblyFileVersion文件版本号:即属性面板中的文件版本,存储在Win32版本资源中,这个号仅供参考,CLR既不会检查,也不关心这个版本号。
- AssemblyInformationVersion:属性面单中的产品版本,存储在Win32版本资源中,当Assembley.cs中未设置此项时,属性中的产品版本将于AssemblyFileVersion保持一致。也是仅供参考,CLR不检查不适用。没什么用。
版本号的格式:major主版本号.minor次版本号.build内部版本号.reversion修订号。
前两个版本号构成了公众对版本的理解。
如果公司每天都编译这个程序集,那build号每天都需要递增。如果一天内需要多次编译程序集,则保持同一个build一致的情况下,增加修订号。
2. 程序集的查找
很多开发者在编写代码过程都有这么一个需求,喜欢把引用第三方的一些dll放到根目录单独的一个文件夹中,使看起来更有条例一点。
比如我们有个控制台程序ConsoleTest,引用一大堆第三方dll,想把这些dll都放到与ConsoleTest.exe同级的一个文件夹subLib1和subLib2里,大致结构可能如下:
- 根目录
- ConsoleTest.exe
- ConsoleTest.exe.config
- subLib1
- a.dll
- b.dll
- subLib2
- c.dll
- d.dll
此时运行程序的话,因为查找不到引用的dll,会报FileNotFoundException
。所以需要在ConsoleTest.exe.config
文件中做如下配置(必须是在应用程序的主程序集文件名的config文件中配置)。
<configuration><runtime><assemblyBinding xmlns:"urn:schemas-microsoft-com:asm.v1"><probing privatePath="subLib1;subLib2" /></assemblyBinding></runtime>
</configuration>
probing
就制定了要查找的字目录,privatePath只能是根目录下的相对目录,不能指向根目录意外的目录。
2.1 CLR查找程序集顺序
这里假如CLR要查找一个AsmName.dll的程序集,而且程序的根目录叫AppDir,subLib1和subLib2已经在privatePath中配置过。查找顺序如下:
- AppDir\AsmName.dll
- AppDir\AsmName\AsmName.dll(上一步没找到,就往AsmName文件夹内找AsmName.dll文件)
- AppDir\subLib1\AsmName.dll
- AppDir\subLib1\AsmName\AsmName.dll
- AppDir\subLib2\AsmName.dll
- AppDir\subLib2\AsmName\AsmName.dll
- 如果再以上各个目录中都没找到目标程序集,则会用exe后缀替换dll后缀继续查找
- AppDir\AsmName.exe
- AppDir\AsmName\AsmName.exe
- AppDir\subLib1\AsmName.exe
- AppDir\subLib1\AsmName\AsmName.exe
- AppDir\subLib2\AsmName.exe
- AppDir\subLib2\AsmName\AsmName.exe
以上查找是基于中性语言文化的查找,如果向AsmName.dll应用了"en-US"语言文化,那么就会这么查找
- AppDir\en-US\AsmName.dll
- AppDir\en-US\AsmName\AsmName.dll
- AppDir\en-US\subLib1\AsmName.dll
- AppDir\en-US\subLib1\AsmName\AsmName.dll
- AppDir\en-US\AsmName.exe
- AppDir\en-US\AsmName\AsmName.exe
- AppDir\en-US\subLib1\AsmName.exe
- AppDir\en-US\subLib1\AsmName\AsmName.exe
- 如果没en-US文件夹或者文件夹内找不到,则会继续找en文件夹
- AppDir\en\AsmName.dll
- AppDir\en\AsmName\AsmName.dll
- AppDir\en\subLib1\AsmName.dll
- AppDir\en\subLib1\AsmName\AsmName.dll
- AppDir\en\AsmName.exe
- AppDir\en\AsmName\AsmName.exe
- AppDir\en\subLib1\AsmName.exe
- AppDir\en\subLib1\AsmName\AsmName.exe
3. 强命名程序集与弱命名程序集
二者的结构完全相同,都有PE头、CLR头、元数据、清单表、IL。不同的是强程序集使用发布者的公钥/私钥进行了签名,对程序集进行了唯一性的标识。
弱程序集只能私有部署,即部署到应用程序的根目录或者字目录。强程序集可以私有部署或全局部署,即也可以部署到一些公有位置,CLR默认会检查这些位置。
3.1 Dll hell问题
全局部署会引起dll hell(dll 地狱)问题:两个公司可能会生成同名的dll,然后这两个强程序集都复制到相同的公有位置,最后一个复制的就是“老大”,造成所有正在使用原程序集的软件无法工作。
所以只根据文件名来区分程序集是不够的,CLR必须支持对程序集进行唯一性标识的机制,这就是强命名程序集。强程序集根据以下四个特征进行唯一性标识:
- 文件名(不含扩展名)
- 版本号(AssemblyVersion)
- 语言文化
- 公钥标记(public key token):从公钥派生出的小哈希值
如下就是两个程序集:
ConsoleFrame, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b77a5csdfgsdfg3434dsqfg
ConsoleFrame, Version=1.0.0.0, Culture="en-US", PublicKeyToken=b77a5csdfgsdfg3434dsqfg
弱程序集的public key token为null
ConsoleFrame, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
3.1.1 对弱程序集签名,使其变成强程序集
右键项目-属性,选择Signing-Sign the assembly即可。
然后在另一个项目中,引用ConsoFrame程序集,可以看到,已经生成了PublicKeyToken。
在这里我们新建另一个程序集ConsoleFrame2,且还用同一个AA.pfx公钥进行签名,可以看到ConsoleFrame与ConsoleFram2的PublicKeyToken完全一致:
即:生成强程序集时,公钥也会被嵌到dll里。
3.1.2 全局程序集缓存GAC
之前有讲过强程序集可以放到一个公共的位置,供所有的程序访问,这个位置就是GAC(Global Assembly Cache)。这个位置不是固定的,不同的CLR版本可以有不同的位置,但一般在以下目录都能发现:
%SystemRoot%\Microsoft.NET\Assembly
GAC目录下有很多子目录,子目录的名称是用算法生成的,不要自己手动把dll复制到某个目录里去,没用。应该使用GACUtil.exe工具复制,一般电脑里都有这个,使用Everything工具全局搜即可。
至此,dll hell问题得到解决。
3.1.3 在你的项目中如何引用强程序集?
- 你知道要引用dll的路径,直接项目上右键-添加引用即可。
- 你不知道引用dll的路径,那编译器CSC.exe会从以下位置开始查找:
- 工作目录
- CSC.exe所在的目录,目录中包含CLR的各种dll文件
- 编译时使用/lib参数指定的目录
- 使用LIB环境变量指定的目录
注意:编译查找dll进行编译的位置可不是程序运行时加载dll的位置,这是两码事。
到这里你应该理解到了.NET为什么会有.NET SDK
和.NET Runtime
两种包可供下载安装了,如果只是运行.net程序而不进行开发那么只下载runtime就行。安装SDK时会安装同一程序集的两套拷贝,一份放到编译器的目录,另一份放到GAC里,而安装runtime只需要放到GAC就行。
【CLR】程序集查找与GAC相关推荐
- 手工部署Sqlserver CLR程序集
以前一直用VS部署Sqlserver CLR程序集简单省事,现在服务器部署在内网了,必须手动更新部署Sqlserver CLR程序集. 开始以为ALTER ASSEMBLY [程序集名称] F ...
- matlab 动态目录调用程序集,C#中如何动态添加程序集查找目录
C#中如何动态添加程序集查找目录 情况如下: 现有三个程序集Main.exe, One.dll, Two.dll.其中One.dll引用了Two.dll, 并且One.dll与Two.dll部署在一起 ...
- CLR via C# 边读边想 03 - 本地程序集和强命名程序集
Two Kinds of Assemblies, Two Kinds of Deployment CLR 支持两种类型的程序集:weakly named assemblies and strongly ...
- 共享程序集和强命名程序集(3):强命名程序集的一些作用
强命名程序集能防篡改 用私钥对程序集进行签名,并将公钥和签名嵌入程序集,CLR就可以炎症程序集未被修改或破坏.程序集安装到GAC时,系统对包含清单的那个文件的内容进行哈希处理,将Hash值与PE文件中 ...
- 重温C# clr 笔记总结
重温C# clr 笔记总结 作者: 字体:[增加 减小] 类型:转载 时间:2013-05-13 我要评论 本篇文章是对以前学习C# clr做的一些笔记,现在拿出来和大家分享下,希望需要的朋友能参考一 ...
- 第 3 章 共享程序集和强命名程序集
3.1 节 两种程序集,两种部署 CLR 支持两种程序集:弱命名程序集(weakly named assembly,即无签名的程序集) 和 强命名程序集(strongly named assembly ...
- C#图解教程 第二十一章 命名空间和程序集
命名空间和程序集 引用其他程序集 在第1章中,我们在高层次上观察了编译过程.编译器接受源代码文件并生称名称为程序集的输出文件.这一章中,我们将详细阐述程序集以及它们是如何生成和部署的.你还会看到命名空 ...
- CLR via C# 之管中窥豹(一)
记得刚毕业那会,看过一阵CLR via C#,由于书中知识对于我来说过于深奥,最终只得放弃.而今重新拾起此书并结合工作中的一些经验,偶有小感就写成随笔分享给大家,便于共同探讨,也能帮助我成长. 执行程 ...
- C#学习笔记——各种头衔的程序集
在学习程序集时,总是发现程序集被冠以各种头衔.程序集按文件数量可分为:单文件程序集和多文件程序集:按是否签名,可分为:普通程序集和强命名程序集:按部署方式,可分为:私有程序集和共享程序集.下面开始分别 ...
- 《CLR via C#:框架设计》读书笔记 - CLR
第一章 CLR的执行模型 1.1 将源代码编译成托管代码 1.2 将托管模块合并成程序集 1.3 加载公共语言运行时 1.4 执行程序集代码 ?托管模块->程序集,区别 ?如何通过清单.元数据找 ...
最新文章
- AOP基本概念、AOP底层实现原理、AOP经典应用【事务管理、异常日志处理、方法审计】...
- pandas 判断数据表中的缺失值
- rust房子 如何拆除_“一户多宅”将陆续清查!违规如何处理?
- PHP用空格分割文本为数组的方法
- 朴素贝叶斯算法注意事项(有待完善)
- c# 从地址拷贝byte_面试必备的 “零拷贝” 问题!从头给你说!
- 导航卫星系统行业调研报告 - 市场现状分析与发展前景预测(2021-2027年)
- Android中Parcelable和Serializable接口用法
- 卫生纸玫瑰花折法5步_手工教程:做一个漂亮的玫瑰花捧花,用折纸表达我喜欢你...
- 数学中最神奇的常数-无理数e的由来
- 转发 微博 Qzone 微信 草根创业英雄时代落幕:贾跃亭戴威们一去不复返
- LuoguP4234_最小差值生成树_LCT
- 计算机专业专业课代号408,2020武汉大学计算机专业课改考408
- 1.1.1 操作系统的层次结构、基本概念、功能和目标
- java 消除png 锯齿_java Graphics2d消除锯齿,使字体平滑显示
- 2021年如何选购华强北AirPods(一次翻车到下车的经历总结的经验)
- 手机5g什么时候普及_5g网络什么时候普及?
- Python!Python!
- 详解磁盘配额的设置方法
- Centos7 使用cobbler搭建PXE网络装机服务器安装Centos、Windows、PE、自定义wim镜像