Microsoft® .NET 框架介绍了几个新功能,旨在简化应用程序发布和解决 DLL Hell。最终用户和开发人员都熟悉版本和发布问题,这些问题会伴随着如今基于组件的系统一同出现。例如,每个最终用户都在他们的机器上安装了一个新的应用程序,没料到已有应用程序神秘地停止了工作。多数开发人员花费时间使用 Regedit,努力保持所有必要的注册项一致以便激活 COM 类。
.NET 框架中用于解决 DLL Hell 问题的设计原则和实现技术是建立在 Microsoft Windows® 2000 的基础上的, Rick Anderson 所著的 The End of DLL Hell(英文)和 David D'Souza, BJ Whalen 及 Peter Wilson 所著的 Implementing Side-by-Side Component Sharing in Applications (Expanded) (英文)中都有说明。.NET 框架提供的许多功能都在这两篇文章中有所描述,包括应用程序隔离和并行组件,用于建立在 .NET 平台的应用程序。您将了解 .NET 平台上提供的版本支持,它能使本地 Windows 应用程序更紧密地汇集。
问题叙述
版本
从客户的角度,最常见的版本问题就是我们所说的 DLL Hell 问题。简单地讲, DLL Hell 是指当多个应用程序试图共享一个公用组件(如某个动态连接库(DLL)或某个组件对象模型(COM)类)时所引发的一系列问题。最典型的情况是,某个应用程序将要安装一个新版本的共享组件,而该组件与机器上的现有版本不向后兼容。虽然刚安装的应用程序运行正常,但原来依赖前一版本共享组件的应用程序也许已无法再工作。在某些情况下,问题的起因更加难以预料。比如,当用户浏览某些 Web 站点时会同时下载某个 Microsoft ActiveX® 控件。如果下载该控件,它将替换机器上原有的任何版本的控件。如果机器上的某个应用程序恰好使用该控件,则很可能也会停止工作。
在许多情况下,用户需要很长时间才会发现应用程序已停止工作。结果往往很难记起是何时的机器变化影响到了该应用程序。用户可能会回忆起一周前安装了一些东西,但安装与目前看到的状态并没有任何明显的关联。 更糟的是,现在很少有诊断工具帮助用户(或帮助他们的技术支持人员)确定有什么问题。
这些问题的原因是应用程序不同组件的版本信息没有由系统记录或加强。而且系统为某个应用程序所做的改变会影响机器上的所有应用程序—现在建立完全从变化中隔离出来的应用程序并不容易。
很难建立一个隔离应用程序的一个原因是当前运行时环境只允许单独版本组件或应用程序的安装。这个限制意味着组件的编写者必须以向后兼容的方式编写他们的代码,否则当他们安装新组件的时候会有终止已有应用程序的风险。实际上,如果可能的话,编写永远向后兼容的代码是非常难的。在 .NET 中,side by side 概念是版本问题的核心。"Side by side" 是在同一台机器上同时运行不同版本的相同组件的能力。使用支持并列的组件,编程人员不必努力维护严格的向后兼容,因为不同的应用程序自由使用某个共享组件的不同版本。
更新:2007 年 11 月
并行执行是在同一台计算机上运行应用程序或组件的多个版本的能力。在同一台计算机上,可以同时安装公共语言运行库的多个版本,还可以同时安装使用运行库的某个版本的应用程序和组件的多个版本。
下图显示了几个应用程序,这些应用程序使用同一计算机上两个不同的运行库版本。应用程序 A、B 和 C 使用运行库 1.0 版,而应用程序 D 使用运行库 1.1 版。
.NET Framework 由公共语言运行库和大约二十四个包含 API 类型的程序集组成。运行库和 .NET Framework 程序集分别采用不同的版本。例如,运行库的 1.0 版实际上是 1.0.3705.0 版,而 .NET Framework 程序集的 1.0 版实际上是 1.0.3300.0 版。
下图显示了在同一台计算机上使用一个组件的两种不同版本的几个应用程序。应用程序 A 和 B 使用组件的 1.0 版,而应用程序 C 使用同一组件的 2.0 版。
利用并行执行,可更好地控制应用程序所绑定的组件的版本,并可更好地控制应用程序所使用的运行库的版本。
在 Microsoft Windows XP 和 .NET Framework 之前,发生 DLL 冲突的原因是应用程序不能区别同一代码的不同的不兼容版本。包含在 DLL 中的类型信息仅绑定到文件名。应用程序无法知道包含在 DLL 中的类型是否同用来生成该应用程序的类型相同。因此,组件的新版本会覆盖旧版本,并会破坏应用程序。
为消除 DLL 冲突,并行执行和 .NET Framework 提供了下列功能:
-
具有强名称的程序集。
并行执行利用具有强名称的程序集将类型信息绑定到程序集的特定版本。这可防止应用程序或组件绑定到程序集的无效版本。具有强名称的程序集还允许同一计算机上存在一个文件的多个版本,并且还允许应用程序使用一个文件的多个版本。有关更多信息,请参具有强名称的程序集。
-
版本识别代码存储。
.NET Framework 在全局程序集缓存中提供了版本识别代码存储。全局程序集缓存是全计算机范围的代码缓存,存在于所有安装了 .NET Framework 的计算机上。它根据版本、区域性和发行者信息存储程序集,并且支持组件和应用程序的多个版本。有关更多信息,请参见全局程序集缓存。
-
隔离。
使用 .NET Framework,您可以创建以隔离方式执行的应用程序和组件,这是并行执行的一个基本组成部分。实施隔离时需要了解正在使用的资源以及在应用程序或组件的多个版本间安全地共享的资源。隔离还包括使用版本特定的方式存储文件。有关隔离的更多信息,请参见 并行 (Side-by-Side) 执行的应用程序和组件的创建指南。
按照设计,.NET Framework 1.0 版和 1.1 版可相互兼容。使用 .NET Framework 1.0 版生成的应用程序应当能够在 1.1 版上运行,而使用 .NET Framework 1.1 版创建的应用程序也应当能够在 1.0 版上运行。但是要注意,.NET Framework 1.1 版中添加的 API 功能无法在 .NET Framework 1.0 版中运行。使用 2.0 版创建的应用程序只能在 2.0 版上运行。2.0 版应用程序不能在 1.1 版或更早的版本上运行。有关运行库兼容性的详尽讨论,请参见 版本兼容性。
.NET Framework 的版本被视为由运行库及其关联的 .NET Framework 程序集构成的单个单元(这一概念称为程序集统一)。可以重定向程序集绑定,使其包括 .NET Framework 程序集的其他版本,但是,重写默认的程序集绑定可能会很危险,因此部署前必须进行严格测试。