热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

《.NET之美》之程序集

一、什么是程序集(Assembly)?经由编译器编译得到的,供CLR进一步编译执行的那个中间产物,在WINDOWS系统中,它一般表现为·dll或者是·exe的格式,但是要注意,它们

一、什么是程序集(Assembly)?

经由编译器编译得到的,供CLR进一步编译执行的那个中间产物,在WINDOWS系统中,它一般表现为·dll或者是·exe的格式,但是要注意,它们跟普通意义上的WIN32可执行程序是完全不同的东西,程序集必须依靠CLR才能顺利执行。 ----百度百科之程序集

程序集可分为两种类型:
(1)、可执行程序,后缀为.exe(GUI,图形用户接口;或CUI,命令行用户接口)
(2)、类库,后缀为.dll
其结构如下图:
技术分享图片

在其构成中,只有PE头、CLR头、清单是必须的。其他均为可选的。

二、程序集结构解析

1、清单(Manifest)

我们要如何去查看一个程序集的清单呢?
此时我们就要借助微软自带的强大的工具ILDASM,此程序如果你要装Visual Studio就会自动帮你装上去,路径在:
C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\ildasm.exe.
这里为了演示方便,我新建了一个程序集AssemblyLib作为演示。我们点击此工具的文件按钮,选择我们那个程序集文件,界面就如下图所示:
技术分享图片

我们点击视图-元信息-显示! 滚动到Assembly就可看到AssemblyDef元数据表
技术分享图片

里面包含了程序集的名称、公钥、版本、程序集特性等信息。我们接着往下翻,就可以看到FileDef表、ExportedTypeDef表、ManifestResourceDef表。FileDef表描述了构成程序集的模块信息、ExportedTypeDef表描述了外部模块中存在的类型信息、ManifestResourceDef表包含的是嵌入到程序集的资源信息。
除了主要的这四张表以外,清单中还包含了AssemblyRef表,此表定义了该程序集所引用的其他程序集信息。
从上面可以看出,清单描述了程序集的几乎一切信息,回答了这样几个问题:“程序集是什么(名称、版本、特性等)”“由什么构成(模块、资源)”和“外部依赖是什么(引用了其他哪些程序集)”。

2、元数据

所谓元数据就是描述数据的数据,这样看来,清单也是属于元数据的一种。
元数据与清单类似,也包含了几张表:
ModuleDef表,包含了当前模块的名称和后缀等信息。
TypeDef表,包含了每个类型的信息,这些信息包括类型名称、类型的基类、标记等信息(public、private等)。
MethodDef表,包含了每个方法的信息,这些信息包括方法名称、签名、标记等信息(public、static、virtual等)。
类似地,还有FieldDef、ParamDef、PropertyDef、EventDef几张表。
类型元数据中除了包含模块中定义的类型以外,还包含外部类型的引用,这些信息包含在另外一组表中:TypeRef、MemberRef。
我们只要知道,类型元数据,定义了程序集中所有类型的信息。

3、程序集资源

程序集中还可以包含资源(Resource),资源可以是字符串,也可以是任何格式的文件,比如图片、Excel文档等。
现在假设我们需要在项目中得到一张图片的资源,我们通常有三种做法:
<1>、将图片保存在程序根目录的文件夹下,然后通过路径获得。
第一种方法我们都很熟悉,这里就不作介绍了。
<2>、将图片作为资源嵌入程序集内。
第二种方法我们平常是比较少遇到的,我们看一下如何去做。
程序集的资源(Resource)是一段具有名称的字节数组。可以将资源想象成一个Dictionay,即一个以string为键,以byte[]
为值的字典。因为字节数组是二进制形式,所以资源可以是任何文件。
将资源嵌入程序集内也有两种方法:
①、将文件直接嵌入程序集
这种方法只要将文件添加到项目中,然后查看文件的"属性",将"生成操作"的值设为嵌入的资源。这里需要注意两点,一是资源加到程序集以后,资源的名称并不等于文件名,VS会自动在文件名前面加上程序集的默认命名空间、文件所在的文件夹名。二是
资源的名称是大小写敏感的。
那我们在程序中如何获取资源呢?
可以在调用Assembly类型的实例方法GetManifestResourceNames()中获得程序集的所有资源名称,接下来调用GetManifestResourceStream()方法获得资源的字节流 。

Assembly asm = Assembly.GetExecutingAssembly(); // 获得当前执行的程序集
string[] nameArray = asm.GetManifestResourceNames(); // 获得资源名称
foreach (string name in nameArray) {
Console.WriteLine(name);
using (Stream s = asm.GetManifestResourceStream(name)) {// 获得字节流
}

②、将.resources资源文件嵌入程序集
在第一种方法,资源在程序集中是零散的,我们为了集中管理资源,可以使用.resx文件将资源嵌入到程序集当中。.resx文件是一个XML格式的文本文件,记录了程序集中包含的资源名称和路径,它是程序开发时的设计工具,通过可视化的方式来对程序集中的资源进行分类和管理。注意.resx只是一个XML文本文件,类似一个资源清单,本身并不是程序集资源。在生
成程序集时,.resx会被自动转换为.resources文件,.resources文件包含了实际的资源文件(例如图片或者音频),并嵌入到程序集当中,但习惯上仍将.resx称作资源文件。
<3>、将资源作为独立程序集
在第二种方法中我们将资源直接嵌入到程序集中,会迅速增大程序集的体积,因此,我们可以将资源单独放在一个单独的程序集中,然后再由主程序集引用它。这样做的好处就是如果主程序没有
用到资源,那么就不用去加载这个程序集。我们可以先引用资源程序集的.dll(假设为res.dll),然后用如下的代码去访问资源程序集的资源:

Assembly asm = Assembly.Load("res");
ResourceManager r = new ResourceManager("Resource", asm);
...

在多语言的应用程序中,通常会将各个不同地区的语言文本作为资源,单独放到各自独立的程序集中,使得应用程序可以根据计算机的本地语言来显示相应资源中的文本。
此时我们只要在项目中新建一个资源文件,Resource.en.resx,在这个资源文件中添加字符串资源,名称为"address",值为"China,GuangDong,Shenzhen"。
重新生成项目,在bin\debug文件夹下,会看多多了一个子文件夹en,其中包含了ConsoleApp.resources.dll文件,该程序集包含了英文版本的资源。类似地,可以创建包含了德
语、日语等其他国家语言的程序集,这种程序集有一个形象的名字,叫做卫星程序集(Satellite Assembly)

Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en");
ResourceManager r = new ResourceManager("ConsoleApp.Resource",
Assembly.GetExecutingAssembly());
string address = r.GetString("address");
Console.WriteLine("address:" + address);

其中的"Thread.CurrentThread.CurrentUICulture=new System.Globalization.CultureInfo("en");"语句,将当前的UI区域性改为了en,即英语地区国家。之后,运行ConsoleApp.exe,会看到显示的输出为:

address:China, Guang Dong, Shenzhen

三、强名称程序集

1、强名称的定义

我们在新建程序集时,对程序集进行命名,那此时怎么命名比较好呢?
比如在上面我们建的程序集Assemblylib,别人也可以建这个名称的程序集,我们如何去比较好的划分呢。首先,我们先对同一个程序集不同版本进行划分,我们给程序集加上版本号以及区域性。 如下图:
技术分享图片

这样之后,我们可以很好地分清自己的程序集之间不会发生冲突,但还是无法区分别人与自己的程序集。
为了解决这个问题,我们可以继续加入公司名、公司的URL以及GUID,这样,这个程序集的规则就有了唯一标识,这个时候就会衍生了另一个问题别人拿到你这个程序集后就可以看到你这个程序集的信息,从而进行仿冒。出于这些考虑,微软选择了使用公钥/私钥非对称加密(RSA)的方式,并结合使用了散列函数(SHA1)来保证:程序集的唯一性、防仿冒性、防篡改性。

2、为程序集赋予强名称

接下来我们看下如何实现防伪冒性:
我们需要用到一个工具SN.exe ,这个工具在你装VS的时候就会自动帮你装好,这个文件笔者的目录为:C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools
我们可以使用vs自带的开发人员命令提示符,此工具笔者在:C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Visual Studio 2017\Visual Studio Tools下 打开命令提示符输入sn.exe,我们可以看到如下图的帮助页面: 技术分享图片

技术分享图片

再输入 sn -k D:\Assemblysnk.snk 回车后就会将秘钥写入D盘根目录下
技术分享图片

我们打开D盘根目录即可看到这个秘钥文件。
技术分享图片

上面的文件中包含公钥及私钥,接下来我们将公钥提取出来并另存为另一个文件。
技术分享图片

从上面的结果可以看出,公钥的字节数很长,有128字节,操作起来很不方便。因此,对公钥进行了散列运算,获得了一个它的8字节的哈希值,也就是公钥标记。由于公钥标记是公钥的摘要,或者“指纹”,它们是对等的,此时我们只要关注公钥标记即可。 我们再将公钥加入程序集规则即可。 单纯加公钥别人可以仿冒,并无多大意义,公私钥对就显出了效果。
我们使用VS,将公私钥对加入签名中。 这样就做到了程序集的防伪冒。(加密部分笔者这里就不一一赘述,有兴趣的请自行了解)。
技术分享图片

总结

在这一部分的阅读学习中,笔者先解释了什么是程序集,分析了程序集的结构,还介绍了在程序集中嵌入资源的几种方法,接下来讲了强名称程序集如何一步步去做到唯一性与防伪。在我们日常的开发过程中,程序集是我们接触最多的文件,平时我们只懂得如何去生成与引用,并不知其具体的原理,这样进一步的了解,对我们以后的开发有着奠定基石的作用!

《.NET之美》之程序集


推荐阅读
  • 本文介绍了如何在 ASP.NET 中设置 Excel 单元格格式为文本,获取多个单元格区域并作为表头,以及进行单元格合并、赋值、格式设置等操作。 ... [详细]
  • LDAP服务器配置与管理
    本文介绍如何通过安装和配置SSSD服务来统一管理用户账户信息,并实现其他系统的登录调用。通过图形化交互界面配置LDAP服务器,确保用户账户信息的集中管理和安全访问。 ... [详细]
  • 如果应用程序经常播放密集、急促而又短暂的音效(如游戏音效)那么使用MediaPlayer显得有些不太适合了。因为MediaPlayer存在如下缺点:1)延时时间较长,且资源占用率高 ... [详细]
  • 网络爬虫的规范与限制
    本文探讨了网络爬虫引发的问题及其解决方案,重点介绍了Robots协议的作用和使用方法,旨在为网络爬虫的合理使用提供指导。 ... [详细]
  • 自定义滚动条美化页面内容
    当页面内容超出显示范围时,为了提升用户体验和页面美观,通常会添加滚动条。如果默认的浏览器滚动条无法满足设计需求,我们可以自定义一个符合要求的滚动条。本文将详细介绍自定义滚动条的实现过程。 ... [详细]
  • 微软推出Windows Terminal Preview v0.10
    微软近期发布了Windows Terminal Preview v0.10,用户可以在微软商店或GitHub上获取这一更新。该版本在2月份发布的v0.9基础上,新增了鼠标输入和复制Pane等功能。 ... [详细]
  • 解决Bootstrap DataTable Ajax请求重复问题
    在最近的一个项目中,我们使用了JQuery DataTable进行数据展示,虽然使用起来非常方便,但在测试过程中发现了一个问题:当查询条件改变时,有时查询结果的数据不正确。通过FireBug调试发现,点击搜索按钮时,会发送两次Ajax请求,一次是原条件的请求,一次是新条件的请求。 ... [详细]
  • 本文详细介绍了如何利用Duilib界面库开发窗体动画效果,包括基本思路和技术细节。这些方法不仅适用于Duilib,还可以扩展到其他类似的界面开发工具。 ... [详细]
  • 本文详细介绍了Java代码分层的基本概念和常见分层模式,特别是MVC模式。同时探讨了不同项目需求下的分层策略,帮助读者更好地理解和应用Java分层思想。 ... [详细]
  • 网站访问全流程解析
    本文详细介绍了从用户在浏览器中输入一个域名(如www.yy.com)到页面完全展示的整个过程,包括DNS解析、TCP连接、请求响应等多个步骤。 ... [详细]
  • 本文介绍了如何使用 CMD 批处理脚本进行文件操作,包括将指定目录下的 PHP 文件重命名为 HTML 文件,并将这些文件复制到另一个目录。 ... [详细]
  • 两个条件,组合控制#if($query_string~*modviewthread&t(&extra(.*)))?$)#{#set$itid$1;#rewrite^ ... [详细]
  • 本文详细介绍了DMA控制器如何通过映射表处理来自外设的请求,包括映射表的设计和实现方法。 ... [详细]
  • 解决Win10下MySQL连接问题:Navicat 2003无法连接到本地MySQL服务器(10061)
    本文介绍如何在Windows 10环境下解决Navicat 2003无法连接到本地MySQL服务器的问题,包括启动MySQL服务和检查配置文件的方法。 ... [详细]
  • Spark中使用map或flatMap将DataSet[A]转换为DataSet[B]时Schema变为Binary的问题及解决方案
    本文探讨了在使用Spark的map或flatMap算子将一个数据集转换为另一个数据集时,遇到的Schema变为Binary的问题,并提供了详细的解决方案。 ... [详细]
author-avatar
帝薩克斯_271
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有