《精通C#》十四章-.NET程序集入门

在书中,这一章节的开头说的是自定义命名空间和使用命名空间,在以我目前有限的经验来说,程序集就是一个类库经过编译之后,所生成的一个在引用命名空间,进而使用该文件中已经定义好的字段,属性以及方法的文件,以.dll作为后缀名。这也是为什么在书本的开头就是以命名空间入手。那么什么是命名空间,最直观的方法就是去定义一个类,在类的内部你会发现,总有一个namespace关键字,后面还会跟随一个字符串作为名称,这个名称就是命名空间的名字,也就是接下来我们所要说的程序集的名称,我们先说说命名空间,在接下来说程序集。命名空间使用using来对不同的程序集进行引用,而且如果在使用一个命名空间的时候,由于命名空间的名称过于冗长,每次书写过于麻烦,就可以使用using为该方法定义一个缩略名,之后使用该命名空间是就可以直接使用该塑料名,而不需要写全名称。而且在一个命名空间内部我们可以再次定义一个命名空间,形成嵌套的命名空间,至于这样的作用,有人说这样子的代码更安全,反正在我看来是没什么卵用。那么,什么又是程序集呢?书上市这样描述的:程序集就是一个以公共语言运行库为宿主,版本化的,自描述的二进制文件。为什么说是以公共语言运行库为宿主呢?要知道,CLR可以将代码编译为IL中间语言,这样就使得我们的代码可以跨语言进行复用,而且可以在任何支持.NET的平台上使用,这样就促进了代码的重复使用。版本化就是可以给一个程序集定义不同的版本,这个有什么作用呢?这样两个不同版本的程序集就可以在一个文件*存,而不会产生冲突。这时候我就会想:为什么需要两个不同版本的程序集呢,我只要把第一个版本的内容进行修改不就可以了吗?这样也许会更方便,都是程序集并不是完全独立的,它们之间有可能存在一些依赖关系,这是候,如果对旧版本的程序集不进行保留,这就可能导致一些依赖与它的程序无法正常运行,所以最好是保留不同版本的程序集,这就又要说明程序是如何制定应该使用哪个程序集的方法了, 在这之前,我们需要先讲解私有程序集和共享程序集。

在我看来所谓的私有程序集就是程序在引用它的时候会自动在程序目录或者子目录下自动生成还程序集的副本,也就是说,程序使用的是程序集的副本,这样在一个程序中若是多次使用该程序集的话就会产生多个副本,这就是多对多的关系,共享程序集目的和私有程序集其实是一样的,旨在一个程序集为多个项目所使用,不同在于它因为部署在一个公共文件夹中,所以它或者说是它的副本被所有引用它的项目所共用(因为程序集部署过去时,其实是在公共文件夹中产生一个副本),当然,这里面的引用路径就必须是该公共文件夹中的程序集的路径了。那么这个文件夹是可以随意一个或者是自己创建的吗?当然不是,这个文件夹的名称叫做全局程序集缓存(GAC),它的确切位置是有机器上所安装的.NET平台的版本决定的,在4.0之前,GAC就是C盘中Windows目录下的Assembly子目录,在在4.0之后,GAC就变成C:windowsMicrosoft.NETassemblyGAC_MSIL,在这里要特别提示,GAC中只能将.dll文件部署为共享程序集,而且不能将可执行的程序集(.exe)安装进去。那么该如何安装.dll文件到GAC中呢?这就要用到安装.net平台之后,自带的Tools文件夹中的的开发人员命令工具,打开命令工具,输入gacutil /?查询gacuti.exe的用法,主要使用到-i将强名称的程序集安装入GAC,使用-u从GAC中卸载程序集,使用-l显示GAV中的程序集的相关信息,带上程序集的友好名称(去掉.dll后缀的名称)就可以查询该程序集的相关信息。在上面提到了强名称,要注意,在部署程序集之前需要先给程序集赋予一个强名称,那么强名称是什么呢?简单来说,强名称就是用于标识给定.NET二进制文件的发行者。在.NET中的作用好比全局唯一表示符,它由一系列的相关数据组成,分别是程序集的友好名称,版本号,公钥,用于本地化的可选的区域性标识,嵌入的数字签名(使用基于程序集内容的散列值和私密钥组成)。那么强名称有什么作用呢,为什么共享程序集强制要求只能是强名称的程序集呢?因为强名称的组成中有一名为散列值,这是基于程序集的内容生成的,可以说是唯一的,也就是说只要一经设置强名称,就算有人恶意的创建一个相同名称的程序集替换原先的那个程序集,在使用的时候经过.NET检测器检测出来,进而停止运行。欲要生成公私钥就需要使用sn.exe工具生成一个文件,这个文件包含两个不同的钥,这个文件一般以*.snk为文件扩展名。那么该如何生成强名称呢?大约在2003年之前,欲要生成强名称的话只有一个方法,那就是使用命令行,还是使用Tools下的开发人员命令提示工具,使用sn生成强名称,至于具体的方法我就不多做缀诉了,因为我们现在有更好用的方法,想要具体了解什么使用sn的自行翻书到p433页或者在网上自行寻找。那么第二种方法又是什么呢?那就是使用vs自带的功能为程序集添加一个强名称,首先,右键点击该类库,选择属性,左边有一栏的选项,选择签名,打钩为程序集签名,之后在选择强名称密钥文件中选择新建,推荐以类库友好名称作为密钥文件名称,记得以.snk作为结尾,至于密码一般是不使用的,这还是看个人吧。这样就可以创建一个强名称的程序集,之后就可以部署入GAC中了,使用共享程序集的方法和一般的程序集是一样的,但是在引用的时候要在浏览中打开GAC文件夹,选中所要引用的程序集,之后一切如同往常一样使用。

现在我们说说该操作才能使得程序正确指向我器所需要的程序集的版本,例:

 <dependentAssembly>
        <assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
        <bindingRedirect oldVersion="0.0.0.0-2.1.0.0" newVersion="2.1.0.0"/>
      </dependentAssembly>

这个例子是我直接从web.config中抠出来的,在<dependentAssembly>元素里面创建<assemblyIdentity>子元素,它用于指定列在客户清单中的程序集的友好名称和一个可选区域(culture)特性,若是要使用默认的区域设置,只需要把这个特性设置为空或者忽略。另外还需要<bindingRedirect>用它来定义程序清单当前指向的版本(oldVersion表示)和GAC中替代的版本(newVersion表示)。但是如果程序是一个桌面引用程序的时候,那就需要在程序中先创建一个App.config,记住,名称必须是App,程序编译之后在bindebug中会有一个已*.exe.config作为后缀的文件,届时把以上的内容保存进去就是了。但是这样写又会在修改版本的时候会有很大的麻烦,因为我需要将config文件的修改内容一个个的发布过去(客户端程序),这样的工作量很大,这就有了发行者策略程序集,作用是运行程序集的发行者在部署程序集的同时,把一个*.config文件的二进制版本也安装到GAC,这样在客户端应用程序那边就不需要包含config文件了,我们使用al.exe工具在命令行创建发行者策略程序集,还需要以下几个参数:1.含有重定向指令的config文件或者xml文件的位置。2.生成的发行者策略程序集的名称,不能仅仅写一个名称,同时需要将发行者程序集输出之后将在哪个文件夹保存的地址。3.用于对发行者策略程序集签名的.snk文件的位置。4.创建的发行者策略程序集的版本号。它是这样的一个字符串:主版本号.次版本号.程序集名.dll,在输出发行者程序集之后,再按照发布全局程序集的方式发布一次就可以了。但是需要记住的是,在发布发行者策略程序集之前,需先将最新的程序集发布至GAC。在书中的这一章节还有一个<codeBase>元素用于指示CLR探测位于网络终点或者客户端应用程序目录以外的本地目录的依赖程序集。当其指向远程计算机的时候,相关具有强名称的程序集会被下载GAC的下载缓存中。但是若是目录是相对于客户端应用程序时,是可以拿来探测不具有强名称的程序集的。