文章目录

  • 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必须支持对程序集进行唯一性标识的机制,这就是强命名程序集。强程序集根据以下四个特征进行唯一性标识:

  1. 文件名(不含扩展名)
  2. 版本号(AssemblyVersion)
  3. 语言文化
  4. 公钥标记(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 在你的项目中如何引用强程序集?

  1. 你知道要引用dll的路径,直接项目上右键-添加引用即可。
  2. 你不知道引用dll的路径,那编译器CSC.exe会从以下位置开始查找:
    • 工作目录
    • CSC.exe所在的目录,目录中包含CLR的各种dll文件
    • 编译时使用/lib参数指定的目录
    • 使用LIB环境变量指定的目录

注意:编译查找dll进行编译的位置可不是程序运行时加载dll的位置,这是两码事。
到这里你应该理解到了.NET为什么会有.NET SDK.NET Runtime两种包可供下载安装了,如果只是运行.net程序而不进行开发那么只下载runtime就行。安装SDK时会安装同一程序集的两套拷贝,一份放到编译器的目录,另一份放到GAC里,而安装runtime只需要放到GAC就行。

【CLR】程序集查找与GAC相关推荐

  1. 手工部署Sqlserver CLR程序集

    以前一直用VS部署Sqlserver CLR程序集简单省事,现在服务器部署在内网了,必须手动更新部署Sqlserver CLR程序集.     开始以为ALTER ASSEMBLY [程序集名称] F ...

  2. matlab 动态目录调用程序集,C#中如何动态添加程序集查找目录

    C#中如何动态添加程序集查找目录 情况如下: 现有三个程序集Main.exe, One.dll, Two.dll.其中One.dll引用了Two.dll, 并且One.dll与Two.dll部署在一起 ...

  3. CLR via C# 边读边想 03 - 本地程序集和强命名程序集

    Two Kinds of Assemblies, Two Kinds of Deployment CLR 支持两种类型的程序集:weakly named assemblies and strongly ...

  4. 共享程序集和强命名程序集(3):强命名程序集的一些作用

    强命名程序集能防篡改 用私钥对程序集进行签名,并将公钥和签名嵌入程序集,CLR就可以炎症程序集未被修改或破坏.程序集安装到GAC时,系统对包含清单的那个文件的内容进行哈希处理,将Hash值与PE文件中 ...

  5. 重温C# clr 笔记总结

    重温C# clr 笔记总结 作者: 字体:[增加 减小] 类型:转载 时间:2013-05-13 我要评论 本篇文章是对以前学习C# clr做的一些笔记,现在拿出来和大家分享下,希望需要的朋友能参考一 ...

  6. 第 3 章 共享程序集和强命名程序集

    3.1 节 两种程序集,两种部署 CLR 支持两种程序集:弱命名程序集(weakly named assembly,即无签名的程序集) 和 强命名程序集(strongly named assembly ...

  7. C#图解教程 第二十一章 命名空间和程序集

    命名空间和程序集 引用其他程序集 在第1章中,我们在高层次上观察了编译过程.编译器接受源代码文件并生称名称为程序集的输出文件.这一章中,我们将详细阐述程序集以及它们是如何生成和部署的.你还会看到命名空 ...

  8. CLR via C# 之管中窥豹(一)

    记得刚毕业那会,看过一阵CLR via C#,由于书中知识对于我来说过于深奥,最终只得放弃.而今重新拾起此书并结合工作中的一些经验,偶有小感就写成随笔分享给大家,便于共同探讨,也能帮助我成长. 执行程 ...

  9. C#学习笔记——各种头衔的程序集

    在学习程序集时,总是发现程序集被冠以各种头衔.程序集按文件数量可分为:单文件程序集和多文件程序集:按是否签名,可分为:普通程序集和强命名程序集:按部署方式,可分为:私有程序集和共享程序集.下面开始分别 ...

  10. 《CLR via C#:框架设计》读书笔记 - CLR

    第一章 CLR的执行模型 1.1 将源代码编译成托管代码 1.2 将托管模块合并成程序集 1.3 加载公共语言运行时 1.4 执行程序集代码 ?托管模块->程序集,区别 ?如何通过清单.元数据找 ...

最新文章

  1. AOP基本概念、AOP底层实现原理、AOP经典应用【事务管理、异常日志处理、方法审计】...
  2. pandas 判断数据表中的缺失值
  3. rust房子 如何拆除_“一户多宅”将陆续清查!违规如何处理?
  4. PHP用空格分割文本为数组的方法
  5. 朴素贝叶斯算法注意事项(有待完善)
  6. c# 从地址拷贝byte_面试必备的 “零拷贝” 问题!从头给你说!
  7. 导航卫星系统行业调研报告 - 市场现状分析与发展前景预测(2021-2027年)
  8. Android中Parcelable和Serializable接口用法
  9. 卫生纸玫瑰花折法5步_手工教程:做一个漂亮的玫瑰花捧花,用折纸表达我喜欢你...
  10. 数学中最神奇的常数-无理数e的由来
  11. 转发 微博 Qzone 微信 草根创业英雄时代落幕:贾跃亭戴威们一去不复返
  12. LuoguP4234_最小差值生成树_LCT
  13. 计算机专业专业课代号408,2020武汉大学计算机专业课改考408
  14. 1.1.1 操作系统的层次结构、基本概念、功能和目标
  15. java 消除png 锯齿_java Graphics2d消除锯齿,使字体平滑显示
  16. 2021年如何选购华强北AirPods(一次翻车到下车的经历总结的经验)
  17. 手机5g什么时候普及_5g网络什么时候普及?
  18. Python!Python!
  19. 详解磁盘配额的设置方法
  20. Centos7 使用cobbler搭建PXE网络装机服务器安装Centos、Windows、PE、自定义wim镜像

热门文章

  1. 回顾2017展望未来
  2. 用于自动驾驶的实时联合目标检测和语义分割网络
  3. android提交sql语句,sql的提交 - 亭子happy的个人页面 - OSCHINA - 中文开源技术交流社区...
  4. 正态分布随机数产生方法
  5. android中RecyclerView添加下划线
  6. 一组绝对有益于科研的随想录(转载)
  7. 获取一组坐标的中心点
  8. 教你如何刻录极品CD音乐碟
  9. Nginx配置移动端和电脑端自动双向跳转(301重定向的实际场景,附带apache配置)
  10. 打印机的系统是linux吗,linux下打印机的配置和使用