注意
本文特定于 .NET Framework。 它不适用于 .NET 的较新版本实现,包括 .NET 6 及更高版本。
可以将编译时绑定引用重定向到 .NET Framework 程序集、第三方程序集或你自己的应用的程序集。 可以通过多种方式重定向应用以使用程序集的不同版本:通过发布者策略、应用配置文件或计算机配置文件。 本文讨论程序集绑定在 .NET Framework 中的工作原理以及如何对其进行配置。
提示
本文特定于 .NET Framework 应用。 有关 .NET 5+ 中程序集加载的信息(和 .NET Core),请参阅 .NET 中的依赖项加载。
程序集统一和默认绑定
有时,.NET Framework 程序集的绑定会通过名为 程序集统一的方式被重定向。 .NET Framework 由公共语言运行时的版本和构成类型库的大约 20 个 .NET Framework 程序集组成。 这些 .NET Framework 程序集由运行时视为单个单元。 默认情况下,在启动应用时,运行时运行的代码中的所有对类型引用都定向到与进程中加载的运行时具有相同版本号的 .NET Framework 程序集。 此模型发生的重定向是运行时的默认行为。
例如,如果应用引用System.XML命名空间中的类型,并且是使用 .NET Framework 4.5 生成的,则它包含对运行时版本 4.5 附带的 System.XML 程序集的静态引用。 如果要将绑定引用重定向到 .NET Framework 4 附带的System.XML程序集,可以将重定向信息放在应用配置文件中。 统一 .NET Framework 程序集的配置文件中的绑定重定向取消该程序集的统一。
此外,如果有多个可用版本,可能需要手动重定向第三方程序集的程序集绑定。
提示
如果更新应用程序间接引用的 NuGet 包,并开始看到新的错误,例如 FileLoadException
、MissingMethodException
、TypeLoadException
或 FileNotFoundException
,则可能需要启用自动绑定重定向或手动添加绑定重定向。 更新 NuGet 包时,这是正常的,并且是针对旧版依赖项生成的一些包的结果。 以下是应用配置文件的摘录,添加了 System.Memory 包的绑定重定向:
<dependentAssembly>
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
</dependentAssembly>
使用发布者策略重定向版本
程序集供应商可以通过将发布者策略文件与新程序集一起,将应用定向到较新版本的程序集。 位于全局程序集缓存中的发布者策略文件包含程序集重定向设置。
每个 major.minor 版本的程序集都具有其自己的发布服务器策略文件。 例如,从版本 2.0.2.222 重定向到 2.0.3.000,从版本 2.0.2.321 重定向到版本 2.0.3.000 都进入同一文件,因为它们与版本 2.0 相关联。 但是,从版本 3.0.0.999 重定向到版本 4.0.0.000 的操作记录在版本 3.0.999 的文件中。 .NET Framework 的每个主版本都有自己的发布者策略文件。
如果程序集存在发布者策略文件,运行时会在检查程序集的清单和应用配置文件后检查此文件。 仅当新程序集与被重定向的程序集向后兼容时,供应商才应使用发布者策略文件。
可以通过在应用配置文件中指定设置来绕过应用的发布者策略,如 绕过发布者策略 部分中所述。
在应用级别重定向版本
通过应用配置文件更改应用的绑定行为有几种不同的方法:可以 手动编辑文件,依赖于自动绑定重定向,也可以通过 绕过发布者策略来指定绑定行为。
手动编辑应用配置文件
可以手动编辑应用配置文件以解决程序集问题。 例如,如果供应商在不提供发布者策略的情况下发布应用使用的程序集的较新版本(因为它们不保证向后兼容),则可以将程序集绑定信息放入应用的配置文件中,引导应用使用较新版本的程序集,如下所示。
<dependentAssembly>
<assemblyIdentity name="someAssembly"
publicKeyToken="32ab4ba45e0a69a1"
culture="en-us" />
<bindingRedirect oldVersion="7.0.0.0" newVersion="8.0.0.0" />
</dependentAssembly>
依赖于自动绑定重定向
在 Visual Studio 中创建面向 .NET Framework 4.5.1 或更高版本的桌面应用时,应用程序使用自动绑定重定向。 这意味着,如果两个组件引用同一强名称程序集的不同版本,运行时会自动将绑定重定向添加到输出应用配置(app.config)文件中程序集的较新版本。 此重定向将重写可能会发生的程序集统一。 源 app.config 文件未修改。 例如,假设你的应用直接引用带外的 .NET Framework 组件,但使用的是面向同一组件旧版本的第三方库。 编译应用时,将修改输出应用配置文件,以包含至组件更新版本的绑定重定向。
如果创建 Web 应用,则会收到有关绑定冲突的生成警告,这反过来又提供了将必要的绑定重定向添加到源 Web 配置文件的选项。
如果手动将绑定重定向添加到源 app.config 文件,在编译时,Visual Studio 会尝试根据添加的绑定重定向来统一程序集。 例如,假设您为一个程序集插入了以下绑定重定向:
<bindingRedirect oldVersion="3.0.0.0" newVersion="2.0.0.0" />
如果应用中的另一个项目引用同一程序集的版本 1.0.0.0,则自动绑定重定向会将以下条目添加到输出 app.config 文件中,以便此程序集的版本 2.0.0.0 上统一应用:
<bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0" />
如果你的应用面向较旧版本的 .NET framework,则可以启用自动绑定重定向。 可以通过在任何程序集的 app.config 文件中提供绑定重定向信息或关闭绑定重定向功能来替代此默认行为。 若要了解如何打开或关闭此功能,请参阅如何:启用和禁用自动绑定重定向。
绕过发布者策略
如有必要,可以在应用配置文件中替代发布者策略。 例如,声明向后兼容的程序集的新版本仍可能会中断应用。 如果要绕过发布服务器策略,请将 <publisherPolicy> 元素添加到应用配置文件中的 <dependentAssembly> 元素,并将 apply
属性设置为 no
,这将替代以前的任何 yes
设置。
<publisherPolicy apply="no" />
绕过发布者策略以让用户保持应用运行,但请确保向程序集供应商报告问题。 如果程序集具有发布者策略文件,供应商应确保程序集向后兼容,并且客户端可以尽可能多地使用新版本。
重定向其他组件使用的测试、插件或库的版本
对于测试,应生成 .dll.config 文件。 加载测试时,大多数现有的单元测试框架都遵循这些文件。
插件可能支持 .dll.config 文件,不过,也可能不会支持。 重定向的唯一可靠机制是在创建 AppDomain 时提供 bindingRedirects
。
你可能会尝试通过 AssemblyResolve 事件处理程序解决此问题,但这不起作用,因为这些处理程序仅在加载失败时调用。 如果程序集加载成功,要么是因为另一个程序集或主机加载了它,要么存在于 GAC 中,则不会调用 AssemblyResolve
处理程序。
在计算机级别重定向版本
计算机管理员希望计算机上的所有应用都使用特定版本的程序集时,可能很少出现这种情况。 例如,特定版本可能会修复安全漏洞。 如果程序集在计算机的配置文件中重定向,称为 machine.config,则使用该旧版本的计算机上的所有应用将定向到使用新版本。 计算机配置文件将替代应用配置文件和发布者策略文件。 此 machine.config 文件位于 32 位计算机的 %windir%\Microsoft.NET\Framework[version]\config\machine.config,或 64 位计算机的 %windir%\Microsoft.NET\Framework64[version]\config\machine.config。
在配置文件中指定程序集绑定
使用相同的 XML 格式指定绑定重定向,无论是在应用配置文件、计算机配置文件还是发布者策略文件中。 若要将一个程序集版本重定向到另一个程序集版本,请使用 <bindingRedirect> 元素。 oldVersion
属性可以指定单个程序集版本或一系列版本。 newVersion
属性应指定单个版本。 例如,<bindingRedirect oldVersion="1.1.0.0-1.2.0.0" newVersion="2.0.0.0"/>
指定运行时应使用版本 2.0.0.0 而不是 1.1.0.0 和 1.2.0.0 之间的程序集版本。
下面的代码示例演示了各种绑定重定向方案。 该示例为 myAssembly
的一系列版本指定重定向,并为 mySecondAssembly
指定单个绑定重定向。 该示例还指定发布者策略文件中的设置不会替代 myThirdAssembly
的绑定重定向。
若要绑定程序集,必须在 <assemblyBinding> 标记中使用 xmlns
属性指定字符串 "urn:schemas-microsoft-com:asm.v1"。
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="myAssembly"
publicKeyToken="32ab4ba45e0a69a1"
culture="en-us" />
<!-- Assembly versions can be redirected in app,
publisher policy, or machine configuration files. -->
<bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="mySecondAssembly"
publicKeyToken="32ab4ba45e0a69a1"
culture="en-us" />
<bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="myThirdAssembly"
publicKeyToken="32ab4ba45e0a69a1"
culture="en-us" />
<!-- Publisher policy can be set only in the app
configuration file. -->
<publisherPolicy apply="no" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
将程序集绑定限制为特定版本
可以在应用配置文件中的 <assemblyBinding> 元素上使用 appliesTo
属性将程序集绑定引用重定向到特定版本的 .NET Framework。 此可选属性使用 .NET Framework 版本号来指示它适用的版本。 如果未指定 appliesTo
属性,<assemblyBinding> 元素将应用于 .NET Framework 的所有版本。
例如,若要重定向 .NET Framework 3.5 程序集的程序集绑定,需要在应用配置文件中包含以下 XML 代码。
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"
appliesTo="v3.5">
<dependentAssembly>
<!-- assembly information goes here -->
</dependentAssembly>
</assemblyBinding>
</runtime>
应按版本顺序输入重定向信息。 例如,输入 .NET Framework 3.5 程序集的绑定重定向信息,然后输入 .NET Framework 4.5 程序集的绑定重定向信息。 最后,输入任何因不使用 appliesTo
特性而适用于所有版本的 .NET Framework 的 .NET Framework 程序集重定向的程序集绑定重定向信息。 如果重定向存在冲突,则使用配置文件中的第一个匹配重定向语句。
例如,若要重定向对 .NET Framework 3.5 程序集的一个引用,以及另一个对 .NET Framework 4 程序集的引用,请使用以下伪代码中显示的模式。
<assemblyBinding xmlns="..." appliesTo="v3.5 ">
<!--.NET Framework version 3.5 redirects here -->
</assemblyBinding>
<assemblyBinding xmlns="..." appliesTo="v4.0.30319">
<!--.NET Framework version 4.0 redirects here -->
</assemblyBinding>
<assemblyBinding xmlns="...">
<!-- redirects meant for all versions of the runtime -->
</assemblyBinding>