【深入理解CLR 三】生成、打包、部署和管理应用程序及类型(下)

简介: 【深入理解CLR 三】生成、打包、部署和管理应用程序及类型(下)

可以将程序集视为一个逻辑的DLL或EXE,一般由含有元数据的PE文件、IL代码文件和一些jpg、gif等资源文件构成。

**如何配置应用程序去下载程序集文件呢?**可以在应用程序配置文件中指定codeBase元素,在codeBase的URL中检查机器的下载缓存,如果有直接加载文件,没有的话去URL位置下载到缓存,如果URL都没有,直接抛出异常FileNotFoundException。

程序集的三大好处:增量下载、代码与资源文件分离、多语言封装

**注意:**对于常用到的那些设置和类型,虽然程序集是逻辑分组的,但您最好还是把它们放到一个文件里,这样可以让CLR缩短以下查找时间,提高下查找性能不是

##构建联系–元数据(清单表)

合并的前提就是清单,只有通过清单,CLR才能知道程序集的具体信息,知道该加载哪些资源文件。换句话说清单就是程序集的自我介绍。

也许各位看着表头疼,一如前例,我简单介绍一下这个自描述清单表的各部分到底有什么:

  • AssemblyDef :程序集名称、版本、语言文化、一些标志、哈希算法、发布者公钥(特别注意,这里不分什么项,描述自身程序集的就这些内容)
  • FileDef:每个PE和资源文件都有记录项,文件名和扩展名、哈希值、标志
  • ManifestResoutceDef:主管资源,资源有两类,独立的资源文件和嵌入PE的资源流,对于独立的资源文件,给个指向FileDef的引用就行,如果是嵌入的,还得给个偏移量,确定资源在PE文件中的起止位置。当然还包括资源名称、一些标志(主要是访问标志)
  • ExportedTypesDef:主管导出类型,所有PE模块中的每个导出类型都都应该有个记录项,包含类型名称,指向FileDef表中的引用以及指向TypeDef的引用。也就是定位到托管模块再定位到类型
    ##合并基本流程
    ###一些开关
    以下几个常用开关可以帮助我们编译指定文件:
  • /t:exe       生成控制台可执行文件 (/target:exe的缩写: )
  • /t:winexe       生成图形界面可执行文件 (/target:exe的缩写: )
  • /t:appcontainerexe       生成WindowsStore执行体 (/target:exe的缩写: )
  • /t:library       生成类库执行体 (/target:exe的缩写: )
  • /t:winmdobj       生成winmd执行体 (/target:exe的缩写: ) (不知道干嘛的 )

总之以上任何命令执行完都会生成程序集,换句话说,都包含清单文件、元数据PE+IL、资源文件(不一定有)三件套。可以直接让CLR操作,**但如果加了这个开关:/t:module这样生成的就是一个托管模块了(不一定准确啊),反正就是不含清单文件,不能直接执行了。**要想执行这个模块,必须得把它加载到别的程序集里,使用这个命令/t:addmodule

###工作流程

####生成程序集文件

假定有两个源代码文件:Java.cs(包含不常用类型)、C#.cs(包含常用类型)。在有了之前的开关的基础上,这里同样用书中举的例子来说明情况吧:

1,首先编译一个非程序集模块:csc /t:module Java.cs因为不常用,所以可以只编译为模块,用的时候再加载到程序集里去。

2,其次编译个常用的程序集模块,顺便再加上那个不常用的已经编译好的模块Java.netmodule

csc /out:C#biggerthanJava.dll /t:library /addmodule:Java.netmodule  C#.cs

/t:addmodule这个开关告诉编译器要将Java.netmodule文件添加到FileDef清单元数据表,并将Java.netmodule的公开导出类型添加到ExportTypesDefe清单元数据表,这儿没涉及到啥资源。和ManifestResoutceDef没啥关系。用图片表示就类似这样:

图片有些许错误哈,jeffrey也说明了,就像FUT,它是主模块,清单文件宿主,所以不应该出现自公开导出类型的。

这下可以在导出类型里看到引用token编号:0x26000001,引入题外话解释0x26啥意思:

0x26就是表示文件嘛,也就是表示引入文件的token号。

####加载程序集文件

经过以上各个步骤,程序集文件C#biggerthanJava.dll 已经生成了,要想用,当然得用命令引进来嘛,/r:C#biggerthanJava.dll 注意所有要引入的文件都必须存在!

  1. 方法首次调用,CLR检测作为参数、返回值或局部变量被引用的类型
  2. CLR试图加载所有引用的程序集中含有的清单文件,如果发现和1中检测到的类型一致的,则登记,总之要登记完所有1中指出的所有文件。注意,咱1中用不到的也就别加载了,浪费性能

##辅助神器–程序集链接器

这个东西的作用简而言之就是你先生成一堆module,用的时候它帮你链接成程序集,用这个方法,上述步骤就该这么来了:

csc /t:module Java.cs

csc /t:module C#.cs

al /out:C#biggerthanJava.dll /t:library Java.netmodule C#.netmodule

生成的程序集就如下所示了:

要是想加入资源文件(咱前边说过资源文件分独立和嵌入两种),也可以直接用命令:/embed加嵌入的和/link加独立的。

##程序集版本资源信息

###程序集版本号组成

通过一些命令或者C#编译器都可以指定程序集的版本信息:这些信息点击任何一个dll的属性都可见:

你可以通过命令(这里就不再详细说了,网上都可以查到)或者VS来直接标明:

这里介绍下版本号,个人感觉java和C#的版本号也很像:

简单来说一下(个人理解啊):拿微信举例吧,微信添加了朋友圈功能,这是大改,主板本号加,朋友圈添加了三天可见,这是小改,次版本号加,这两个是公众感受的。咱开发的时候,对于朋友圈三天可见这个dll每改一天生成一次,build加一,如果一天生成两次了,说明第一次生成有bug,咱改个bug,修订号review加一。

###程序集的三个版本号

  • AssemblyFileVersion:简单理解就是文件每发生更新(主次版本号先设置好),版本号就加,机器自动加,windows资源管理器可见。
  • AssemblyInformationalVersion:简单理解就是文件每发生更新(主次版本号先设置好),版本号就加,不同的是,内部和修订号人工打包标记
  • AssemblyVersion:最重要的版本号!唯一标识程序集,存储在AssemblyDef清单元数据表里,也就是之前提到的清单元数据表里的版本号
    ##语言文化

    不能每一种语言都开发一种代码吧,所以生成程序集应该指定为语言文化中性,然后把各种语言文化打包为附属程序集(专门放资源文件和语言文化这类不含代码的文件的),这样,用到的时候直接加载(使用/c:text指定,这里目录名称要符合语言文化,也就是上述那张表)就好:举个例子

    #程序集的部署与控制
    ##.NetFrameWork部署目标
    在COM时代(虽然根本没经历过COM时代),但凭使用感受说话吧:
    1,安装一个应用程序导入了一个dll,一连串的报错,其它dll受到影响了(DLL HILL问题)
    2,安装和卸载复杂,垃圾注册表根本清不干净。
    3,安全性不高,用户不能完全控制。
    部署目标也就是针对以上三个问题吧:解决DLL hell问题,不依赖注册表,将安全权限完全赋予给用户。
    ##简单应用程序部署
    ###对于windows Store的官方程序
  • vs会将所有必要程序集打包为一个.appx文件,用户安装该文件时,所有程序集进入一个目录
  • CLR从目录加载程序集,windows在桌面添加磁贴,若其它用户安装该appx,windows只添加磁铁(因为程序集已经在第一次加载好了呀)
  • 删除时,如果有很多用户安装,只删不想要的用户的磁贴,如果都不想要,则删程序集。
    ###对于非官方开发者
  • 只需要把全部代码复制粘贴到光盘里,所有引用的程序集都在里边,所以摆脱注册表了,这也许就是咱常说的离线安装包下载吧
  • 用cab格式,打包成msi文件,联网按需下载。这也许就是在线安装吧
    ##简单管理控制
    ###管理程序集文件
    其实主要是CLR定位和加载用的,假定发布者想把应用程序中一个程序集文件(MutiFileLibrary.dll)放到其它地方(也就是不在该应用程序所包含的程序集文件下),那么就需要配置文件:

    结构类似这样,这样就可以通过Program.exe.config找到所有文件

    该配置文件指明了,要去AuxFile子目录去查找,通过probing元素的privatePath特性。CLR先从应用程序基目录查找,找不到再按照配置路径**(配置路径都应为相对基目录的路径)**找。通常网站的配置文件就是Web.confg
    ###管理CLR
    通过Machine.config来管理CLR,每一个CLR均对应一个Machine.config

全文到这里就结束了,整篇博文所讲的是**模块是如何生成,程序集又是如何生成的,CLR是如何加载程序集的(简述)。**完成的过程中也在思考一个问题,微软的元数据结构似乎是优于java的class文件结构的,微软的版本号策略似乎也比java的结构清晰。但为何如今发展起来这么缓慢,究其原因,可能就是之前没开源吧,果然开源改变世界啊。最近也一直在思考职业规划,如果要在C#这条路上前进,无疑得使用微软全套(虽然很爽但窄),现在搞的比较好的Azure云势头似乎正在追赶亚马逊的Aws,未来的开发真的会迎来云编译时代么?感觉前景较好的是.netcore和uwp编程以及基于.netFramework的Azure。

相关文章
|
2月前
|
Prometheus 监控 Cloud Native
应用程序部署
应用程序部署
51 3
|
监控 安全 虚拟化
DLL注入的环境构建
DLL注入的环境构建
|
开发框架 自然语言处理 安全
【深入理解CLR 三】生成、打包、部署和管理应用程序及类型(上)
【深入理解CLR 三】生成、打包、部署和管理应用程序及类型(上)
99 0
|
JavaScript 前端开发 缓存
SharePoint Framework 在web部件中使用已存在的JavaScript库 - 捆绑打包和外部引用
在构建SPFx客户端web部件时,你可以使用公网已有的JavaScript库来构建强大的解决方案。但是在使用的时候你需要考虑你引用的东西没有影响SharePoint页面的性能。
5489 0