C++ Programmer's Cookbook

{C++ 基础} {C++ 高级} {C#界面,C++核心算法} {设计模式} {C#基础}

程序集

程序集是 .NET Framework 应用程序的构造块;程序集构成了部署、版本控制、重复使用、激活范围控制和安全权限的基本单元。程序集是为协同工作而生成的类型和资源的集合,这些类型和资源构成了一个逻辑功能单元。程序集为公共语言运行库提供它识别类型实现所需的信息。对于运行库,类型不存在于程序集上下文之外。


程序集是 .NET Framework 编程的基本组成部分。程序集执行以下功能:

  • 包含公共语言运行库执行的代码。如果可移植可执行 (PE) 文件没有相关联的程序集清单,则将不执行该文件中的 Microsoft 中间语言 (MSIL) 代码。请注意,每个程序集只能有一个入口点(即 DllMainWinMainMain)。
  • 程序集形成安全边界。程序集就是在其中请求和授予权限的单元。有关应用于程序集的安全边界的更多信息,请参见程序集安全注意事项
  • 程序集形成类型边界。每一类型的标识均包括该类型所驻留的程序集的名称。在一个程序集范围内加载的 MyType 类型不同于在其他程序集范围内加载的 MyType 类型。
  • 程序集形成引用范围边界。程序集的清单包含用于解析类型和满足资源请求的程序集元数据。它指定在该程序集之外公开的类型和资源。该清单还枚举它所依赖的其他程序集。
  • 程序集形成版本边界。程序集是公共语言运行库中最小的可版本化单元,同一程序集中的所有类型和资源均会被版本化为一个单元。程序集的清单描述您为任何依赖项程序集所指定的版本依赖性。有关版本控制的更多信息,请参见程序集版本控制
  • 程序集形成部署单元。当一个应用程序启动时,只有该应用程序最初调用的程序集必须存在。其他程序集(例如本地化资源和包含实用工具类的程序集)可以按需检索。这就使应用程序在第一次下载时保持精简。有关部署程序集的更多信息,请参见部署应用程序
  • 程序集是支持并行执行的单元。有关运行多个程序集版本的更多信息,请参见程序集和并行 (side-by-side) 执行

程序集可以是静态的或动态的。静态程序集可以包括 .NET Framework 类型(接口和类),以及该程序集的资源(位图、JPEG 文件、资源文件等)。静态程序集存储在磁盘上的可移植可执行 (PE) 文件中。您还可以使用 .NET Framework 来创建动态程序集,动态程序集直接从内存运行并且在执行前不存储到磁盘上。您可以在执行动态程序集后将它们保存在磁盘上。

有几种创建程序集的方法。您可以使用过去用来创建 .dll 或 .exe 文件的开发工具,例如 Visual Studio .NET。您可以使用在 .NET Framework SDK 中提供的工具来创建带有在其他开发环境中创建的模块的程序集。您还可以使用公共语言运行库 API(例如 Reflection.Emit)来创建动态程序集。
NET Framework 开发员指南  

程序集的优点

程序集旨在简化应用程序部署并解决在基于组件的应用程序中可能出现的版本控制问题。

最终用户和开发人员比较熟悉当今基于组件的系统所产生的版本控制和部署问题。一些最终用户曾经历过在计算机上安装新应用程序失败的事情,发现已有应用程序突然停止工作。许多开发人员花费了大量的时间来使所有必需的注册表项保持一致,以便激活 COM 类。

通过在 .NET Framework 中使用程序集,许多开发问题得以解决。因为程序集是不依赖于注册表项的自述组件,所以程序集使无相互影响的应用程序安装成为可能。程序集还使应用程序的卸载和复制得以简化。

版本控制问题

目前,Win32 应用程序存在两类版本控制问题:

  • 版本控制规则不能在应用程序的各段之间表达,并且不能由操作系统强制实施。目前的办法依赖于向后兼容,而这通常很难保证。接口定义一经发布就必须是静态的,并且单段代码必须保持与以前版本向后兼容。此外,通常要对代码进行设计,以便在任意给定时间在计算机上只能出现和执行代码的一个版本。
  • 没有办法在创建到一起的多套组件集与运行时提供的那套组件之间保持一致。

这两类版本控制问题结合在一起产生了 DLL 冲突,在这些冲突中,安装一个应用程序可能会无意间破坏现有的应用程序,因为所安装的某个软件组件或 DLL 与以前的版本不完全向后兼容。出现此情况后,系统不支持诊断和解决此问题。

最终解决 DLL 冲突

Microsoft® Windows® 2000 开始致力于解决这些问题。它所提供的两个功能可以部分地解决 DLL 冲突:

  • Windows 2000 使您能够创建这样的客户端应用程序,其中的 .dll 依赖文件与该应用程序的 .exe 文件位于相同的目录中。Windows 2000 经过配置,能够在检查完全限定的路径或搜索常规路径前,检查 .exe 文件所在目录中的组件。这使组件可以独立于其他应用程序所安装和使用的组件。
  • Windows 2000 锁定 System32 目录中随操作系统提供的文件,使这些文件不会在安装应用程序时被无意替换。

公共语言运行库使用程序集来继续致力于 DLL 冲突的彻底解决。

程序集解决方案

为了解决版本控制问题以及导致 DLL 冲突的其余问题,运行库使用程序集来执行以下功能:

  • 使开发人员能够指定不同软件组件之间的版本规则。
  • 提供强制实施版本控制规则的结构。
  • 提供允许同时运行多个版本的软件组件(称作并行执行)的基本结构。

程序集内容

通常,静态程序集可能由以下四个元素组成:

  • 程序集清单,包含程序集元数据。
  • 类型元数据。
  • 实现这些类型的 Microsoft 中间语言 (MSIL) 代码。
  • 资源集。

只有程序集清单是必需的,但也需要类型或资源来向程序集提供任何有意义的功能。

程序集中的这些元素有分组几种方法。您可以将所有元素分组到单个物理文件中,如下图所示。

单文件程序集

或者,可以将一个程序集的元素包含在几个文件中。这些文件可能是编译代码的模块 (.netmodule)、资源(例如 .bmp 或 .jpg 文件)或应用程序所需的其他文件。在您希望组合以不同语言编写的模块并优化应用程序的下载过程时,可创建一个多文件程序集,优化下载过程的方法是将很少使用的类型放入只在需要时才下载的模块中。

在下图中,一个假想应用程序的开发人员已选择将一些实用工具代码单独放入另一个模块中,同时在其原文件中保留一个较大的资源文件(在此例中为一个 .bmp 图像)。.NET Framework 只在文件被引用时下载该文件;通过将很少引用的代码保留在独立于应用程序的文件中来优化代码下载。

多文件程序集

注意   构成多文件程序集的那些文件实际上并非由文件系统来链接。它们而是通过程序集清单进行链接,公共语言运行库将这些文件作为一个单元来管理。

在此插图中,所有三个文件均属于一个程序集,如 MyAssembly.dll 所包含的程序集清单文件中所述。对于该文件系统,这三个文件是三个独立的文件。请注意,文件 Util.netmodule 被编译为一个模块,因为它不包含任何程序集信息。在创建了程序集后,该程序集清单就被添加到 MyAssembly.dll,指示程序集与 Util.net 模块和 Graphic.bmp 的关系。

现在设计源代码时,您会作出有关如何将应用程序的功能划分到一个或多个文件的明确的决定。在设计 .NET Framework 代码时,您也将作出类似的决定,即如何将应用程序的功能划分到一个或多个程序集中。

全局程序集缓存

安装有公共语言运行库的每台计算机都具有称为全局程序集缓存的计算机范围内的代码缓存。全局程序集缓存中存储了专门指定给由计算机中若干应用程序共享的程序集。

应当仅在需要时才将程序集安装到全局程序集缓存中以进行共享。一般原则是:程序集依赖项保持专用,并在应用程序目录中定位程序集,除非明确要求共享程序集。另外,不必为了使 COM interop 或非托管代码可以访问程序集而将程序集安装到全局程序集缓存。

注意   在有些情况下,您显然不希望将程序集安装到全局程序集缓存中。如果您将组成应用程序的某个程序集置于全局程序集缓存中,则将不再能够通过使用 xcopy 命令复制应用程序目录来复制或安装该应用程序。您还必须在全局程序集缓存中移动该程序集。

有若干方法可以将程序集部署到全局程序集缓存中:

  • 使用专用于全局程序集缓存的安装程序。该方法是将程序集安装到全局程序集缓存的首选方法。
  • 使用 .NET Framework SDK 所提供的名为全局程序集缓存工具 (Gacutil.exe) 的开发人员工具。
  • 使用 Windows 资源管理器将程序集拖到缓存中。
    注意   在部署方案中,应该使用 Windows 安装程序 2.0 将程序集安装到全局程序集缓存中。我们一般只在开发方案中使用 Windows 资源管理器或全局程序集缓存工具,这是因为它们不提供使用 Windows 安装程序时可以提供的程序集引用计数功能和其他功能。

管理员通常使用访问控制列表 (ACL) 来保护 WINNT 目录,以控制写入和执行访问。因为全局程序集缓存安装在 WINNT 目录中,它继承了目录的 ACL。建议只允许具有“管理员”权限的用户从全局程序集缓存中删除文件。

在全局程序集缓存中部署的程序集必须具有强名称。将一个程序集添加到全局程序集缓存时,必须对构成该程序集的所有文件执行完整性检查。缓存执行这些完整性检查以确保程序集未被篡改(例如,当文件已更改但清单未反映此更改时)。

 

程序集安全注意事项

在您生成程序集时,您可以指定该程序集运行所需的一组权限。是否将特定的权限授予程序集是基于证据的。

使用证据有两种截然不同的方式:

  • 将输入证据与加载程序所收集的证据合并,以创建用于策略决策的最终证据集。使用这种语义的方法包括 Assembly.LoadAssembly.LoadFromActivator.CreateInstance
  • 原封不动地使用输入证据作为用于策略决策的最终证据集。使用这种语义的方法包括 Assembly.Load(byte[])AppDomain.DefineDynamicAssembly()

通过在将运行程序集的计算机上设置安全策略,您可以授予一些可选的权限。如果您希望代码可以处理所有潜在的安全异常,可以执行以下操作之一:

  • 为您的代码必须具有的所有权限插入权限请求,并预先处理在未授予权限时发生的加载时错误。
  • 不要使用权限请求来获取您的代码可能需要的权限,但一定要准备处理在未授予权限时发生的安全异常。
    注意   安全性是一个较为复杂的领域,您将要作出很多选择。有关更多信息,请参见安全性的基础概念

在加载时,程序集的证据用作安全策略的输入。安全策略是由企业和计算机的管理员以及用户策略设置建立的,它在执行时确定向所有托管代码授予的权限组。可以为程序集的发行者建立(如果该程序集具有符号代码签名)安全策略,或者为该程序集的下载 Web 站点和区域(就 Internet Explorer 而言)建立安全策略,也可以为该程序集的强名称建立该策略。例如,一台计算机的管理员可以建立这样一种安全策略:它允许从某一 Web 站点下载由指定软件公司签发用以访问计算机上的数据库的所有代码,但不授予对该计算机磁盘的写访问权。

具有强名称的程序集和符号代码

您可以通过两种不同但互为补充的方式签发程序集:使用强名称或使用 Signcode.exe。使用强名称对程序集签名的过程将向包含程序集清单的文件添加公钥加密。强名称签名帮助验证名称的唯一性,避免名称哄骗,并在解析引用时向调用方提供某些标识。

但是,没有任何信任级别与一个强名称相关联,这使符号代码十分重要。符号代码要求发行者向第三方证书颁发机构证实其标识并获取证书。然后此证书将嵌入到您的文件中,并且管理员能够使用该证书来决定是否相信这些代码的真实性。

您可以将强名称和符号代码数字签名一起提供给程序集,或者您可以单独使用其中之一。符号代码一次只能签发一个文件,对于多文件程序集,您可以签发包含程序集清单的文件。强名称存储在包含程序集清单的文件中,但符号代码签名存储在该程序集清单所在的可移植可执行 (PE) 文件中专门保留的槽中。当您已经具有依赖于符号代码签名的信任层次结构或者当您的策略只使用密钥部分并且不检查信任链时,就可以使用程序集的符号代码签发功能(带或不带强名称)。

注意   在一个程序集上同时使用强名称和符号代码签名时,必须首先分配强名称。

公共语言运行库还将执行哈希验证;程序集清单包含构成该程序集的所有文件的列表,包括当生成清单时存在的每一文件的散列。在加载每一文件时,其内容被散列化并与清单中存储的哈希值进行比较。 如果两个哈希值不匹配,则无法加载该程序集。

因为强名称和符号代码确保了完整性,因此您可以将代码访问安全策略建立在这两种形式的程序集证据的基础上。强名称和符号代码签发通过数字签名和证书确保完整性。上面提到的所有技术(哈希验证、强名称和符号代码)共同作用,确保程序集没有做过任何方式的改动。

程序集版本控制

使用公共语言运行库的程序集的所有版本控制都在程序集级别上进行。一个程序集的特定版本和依赖程序集的版本在该程序集的清单中记录下来。除非被配置文件(应用程序配置文件、发行者策略文件和计算机的管理员配置文件)中的显式版本策略重写,否则运行库的默认版本策略是,应用程序只与它们生成和测试时所用的程序集版本一起运行。

注意   仅对具有强名称的程序集进行版本控制。

运行库执行以下几步来解析程序集绑定请求:

  1. 检查原程序集引用,以确定该程序集的版本是否被绑定。
  2. 检查所有适用的配置文件以应用版本策略。
  3. 通过原程序集引用和配置文件中指定的任何重定向来确定正确的程序集,并且确定应绑定到调用程序集的版本。
  4. 检查全局程序集缓存和在配置文件中指定的基本代码,然后使用在运行库如何定位程序集中解释的探测规则检查该应用程序的目录和子目录。

下图说明了这些步骤。

解析程序集绑定请求

有关配置应用程序的更多信息,请参见配置文件。有关绑定策略的更多信息,请参见运行库如何定位程序集

版本信息

每一程序集都用两种截然不同的方法来表示版本信息:

  • 程序集的版本号,该版本号与程序集名称及区域性信息都是程序集标识的组成部分。该号码将由运行库用来强制实施版本策略,它在运行时的类型解析进程中起着重要的作用。
  • 信息性版本,这是一个字符串,表示仅为提醒的目的而包括的附加版本信息。

程序集版本号

每一程序集都有一个版本号作为其标识的一部分。因此,如果两个程序集具有不同的版本号,运行库就会将它们视作完全不同的程序集。此版本号实际表示为具有以下格式的四部分号码:

<major version>.<minor version>.<build number>.<revision>

例如,版本 1.5.1254.0 中的 1 表示主版本,5 表示次版本,1254 表示内部版本号,而 0 则表示修订号。

版本号与其他标识信息(包括程序集名称和公钥,以及与该应用程序所连接的其他程序集的关系和标识有关的信息)一起存储在程序集清单中。

在生成程序集时,开发工具将把每一个被引用程序集的依赖项信息记录在程序集清单中。运行库将这些版本号与管理员、应用程序或发行者设置的配置信息结合使用,以加载被引用程序集的正确版本。

为进行版本控制,运行库会区分常规程序集和具有强名称的程序集。只对具有强名称的程序集执行版本检查。

有关指定版本绑定策略的信息,请参见配置文件。有关运行库如何使用版本信息查找特定程序集的信息,请参见运行库如何定位程序集

程序集信息性版本

信息性版本是一个字符串,它仅出于提醒的目的将附加的版本信息附加到一个程序集;此信息不在运行时使用。基于文本的信息性版本相当于产品的营销广告、包装或产品名称,不被运行库使用。例如,信息性版本可以是“公共语言运行库版本 1.0”或“NET Control SP 2”。

信息性版本使用自定义属性 System.Reflection.AssemblyInformationalVersionAttribute 来表示。有关信息性版本属性的更多信息,请参见设置程序集属性

程序集位置

对于大多数 .NET Framework 应用程序而言,您可以在以下位置找到构成该应用程序的程序集,这些位置包括:该应用程序的目录中,该应用程序目录的子目录中,或全局程序集缓存中(如果该程序集是共享的话)。可以通过在配置文件中使用 <codeBase> 元素重写公共语言运行库查找某一程序集的位置。如果该程序集没有强名称,则使用 <codeBase> 元素指定的位置将被限制在应用程序目录或子目录中。如果程序集具有强名称,则 <codeBase> 能够指定计算机或网络上的任意位置。

当在使用非托管代码或 COM interop 应用程序的过程中查找程序集的位置时,类似的规则同样适用:如果该程序集将由多个应用程序共享,则此程序集应被安装到全局程序集缓存中。和非托管代码一起使用的程序集必须作为类型库导出并注册。由 COM interop 使用的程序集必须在目录中进行注册,尽管有些情况下会自动进行此注册。

程序集和并行 (side-by-side) 执行

并行执行是在同一台计算机上存储和执行应用程序或组件的多个版本的能力。这意味着在同一台计算机上可以同时有运行库的多个版本,并且可以有使用其中某个运行库版本的应用程序和组件的多个版本。并行执行使您能够更多地控制应用程序绑定到的组件版本和应用程序使用的运行库版本。

支持并行存储和执行同一程序集的不同版本是强命名中不可缺少的部分,这种支持内置于运行库基础结构中。因为强名称程序集的版本号是其标识的一部分,所以运行库能够在全局程序集缓存中存储同一程序集的多个版本,并且在运行时加载这些程序集。

尽管运行库使您能够创建并行应用程序,但并行执行并不是自动进行的。有关创建并行执行的应用程序的更多信息,请参见并行执行的编程暗示。

-----------------------------------------

相关章节

使用程序集编程
描述程序集上的属性的创建、签名和设置过程。
发出动态程序集
描述如何创建动态程序集。

posted on 2006-01-05 09:07 梦在天涯 阅读(1166) 评论(0)  编辑 收藏 引用 所属分类: C#/.NET


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


公告

EMail:itech001#126.com

导航

统计

  • 随笔 - 461
  • 文章 - 4
  • 评论 - 746
  • 引用 - 0

常用链接

随笔分类

随笔档案

收藏夹

Blogs

c#(csharp)

C++(cpp)

Enlish

Forums(bbs)

My self

Often go

Useful Webs

Xml/Uml/html

搜索

  •  

积分与排名

  • 积分 - 1795777
  • 排名 - 5

最新评论

阅读排行榜