首页 > 解决方案 > 以 .Net 框架为目标时消除程序集绑定重定向

问题描述

我们有一个包含 100 多个项目的解决方案(大型丑陋的 .Net Framework Monolith 应用程序的一部分)。现在,我们正在推动将尽可能多的代码作为 NuGet 包移动到我们的内部存储库。但是现在我们处于依赖地狱中,因为即使我们所有的代码都是未签名的,大多数第 3 方 NuGet 都是已签名的。以及所有 Microsoft 软件包。

自从我们从 packages.config 迁移到 PackageReference 后,情况变得更糟,因为许多依赖项变得隐含(传递性)。一方面我们想使用 PackageReference,因为:

  1. 在可能的情况下,它离转向 SDK 风格的项目更近了一步。
  2. 准确地说,因为它显示了我们使用的东西,而不会让项目与传递的 deps 混淆。
  3. 这是未来,对吧?

但另一方面,对所有这些绑定重定向进行排序是地狱般的。最糟糕的是 - 从 msbuild 到 VS IDE 并不一致,请参阅为什么控制台构建生成的 project.assets.json 与 VS IDE 构建生成的完全不同?

我想一劳永逸地摆脱它们。我的想法是:

  1. 禁止所有与绑定重定向相关的警告 - MSB3277 和 MSB3247
  2. 从所有配置文件中删除它们
  3. 使用专用代码在运行时解析程序集

我想知道是否有人尝试过这种方法。不能说我们是唯一在绑定重定向中苦苦挣扎的人,这种折磨无疑是因为编程.Net而不是Java而对我们造成的。

我有一个具体的问题 - 是否有人成功地在运行时用逻辑替换了所有配置时间程序集绑定重定向?我想抑制所有与绑定重定向相关的警告并一劳永逸地忘记它们,同时留在.Net Framework(不是Core)领域。

编辑 1

因此,希望看到我们拥有的具体绑定重定向警告示例。好的:

MSB3247: Found conflicts between different versions of the same dependent assembly. In Visual Studio, double-click this warning (or select it and press Enter) to fix the conflicts; otherwise, add the following binding redirects to the "runtime" node in the application configuration file: <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"><dependentAssembly><assemblyIdentity name="System.Buffers" culture="neutral" publicKeyToken="cc7b13ffcd2ddd51" /><bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" /></dependentAssembly></assemblyBinding><assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"><dependentAssembly><assemblyIdentity name="System.Diagnostics.DiagnosticSource" culture="neutral" publicKeyToken="cc7b13ffcd2ddd51" /><bindingRedirect oldVersion="0.0.0.0-4.0.3.1" newVersion="4.0.3.1" /></dependentAssembly></assemblyBinding><assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"><dependentAssembly><assemblyIdentity name="System.Memory" culture="neutral" publicKeyToken="cc7b13ffcd2ddd51" /><bindingRedirect oldVersion="0.0.0.0-4.0.1.1" newVersion="4.0.1.1" /></dependentAssembly></assemblyBinding><assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"><dependentAssembly><assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" culture="neutral" publicKeyToken="b03f5f7f11d50a3a" /><bindingRedirect oldVersion="0.0.0.0-4.0.6.0" newVersion="4.0.6.0" /></dependentAssembly></assemblyBinding> [C:\xyz\tip\Services\Platform\WBDataSvc\TestServices\TestServices.csproj]
MSB3247: Found conflicts between different versions of the same dependent assembly. In Visual Studio, double-click this warning (or select it and press Enter) to fix the conflicts; otherwise, add the following binding redirects to the "runtime" node in the application configuration file: <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"><dependentAssembly><assemblyIdentity name="System.Buffers" culture="neutral" publicKeyToken="cc7b13ffcd2ddd51" /><bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" /></dependentAssembly></assemblyBinding><assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"><dependentAssembly><assemblyIdentity name="System.Memory" culture="neutral" publicKeyToken="cc7b13ffcd2ddd51" /><bindingRedirect oldVersion="0.0.0.0-4.0.1.1" newVersion="4.0.1.1" /></dependentAssembly></assemblyBinding><assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"><dependentAssembly><assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" culture="neutral" publicKeyToken="b03f5f7f11d50a3a" /><bindingRedirect oldVersion="0.0.0.0-4.0.6.0" newVersion="4.0.6.0" /></dependentAssembly></assemblyBinding> [C:\xyz\tip\Services\Platform\DeviceServices\DeviceServices.csproj]
MSB3247: Found conflicts between different versions of the same dependent assembly. In Visual Studio, double-click this warning (or select it and press Enter) to fix the conflicts; otherwise, add the following binding redirects to the "runtime" node in the application configuration file: <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"><dependentAssembly><assemblyIdentity name="System.Buffers" culture="neutral" publicKeyToken="cc7b13ffcd2ddd51" /><bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" /></dependentAssembly></assemblyBinding><assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"><dependentAssembly><assemblyIdentity name="System.Memory" culture="neutral" publicKeyToken="cc7b13ffcd2ddd51" /><bindingRedirect oldVersion="0.0.0.0-4.0.1.1" newVersion="4.0.1.1" /></dependentAssembly></assemblyBinding><assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"><dependentAssembly><assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" culture="neutral" publicKeyToken="b03f5f7f11d50a3a" /><bindingRedirect oldVersion="0.0.0.0-4.0.6.0" newVersion="4.0.6.0" /></dependentAssembly></assemblyBinding> [C:\xyz\tip\Services\Platform\WBDataSvc\DataSvc\DataSvc.csproj]
MSB3247: Found conflicts between different versions of the same dependent assembly. In Visual Studio, double-click this warning (or select it and press Enter) to fix the conflicts; otherwise, add the following binding redirects to the "runtime" node in the application configuration file: <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"><dependentAssembly><assemblyIdentity name="System.Buffers" culture="neutral" publicKeyToken="cc7b13ffcd2ddd51" /><bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" /></dependentAssembly></assemblyBinding><assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"><dependentAssembly><assemblyIdentity name="System.Memory" culture="neutral" publicKeyToken="cc7b13ffcd2ddd51" /><bindingRedirect oldVersion="0.0.0.0-4.0.1.1" newVersion="4.0.1.1" /></dependentAssembly></assemblyBinding><assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"><dependentAssembly><assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" culture="neutral" publicKeyToken="b03f5f7f11d50a3a" /><bindingRedirect oldVersion="0.0.0.0-4.0.6.0" newVersion="4.0.6.0" /></dependentAssembly></assemblyBinding> [C:\xyz\tip\Services\Platform\WBDataSvc\MobileWebService\MobileWebService.csproj]
MSB3277: Found conflicts between different versions of "System.Diagnostics.DiagnosticSource" that could not be resolved.  These reference conflicts are listed in the build log when log verbosity is set to detailed. [C:\xyz\tip\ServerJobs\BackgroundJobTests\BackgroundJobTests.csproj]
MSB3277: Found conflicts between different versions of "System.Diagnostics.DiagnosticSource" that could not be resolved.  These reference conflicts are listed in the build log when log verbosity is set to detailed. [C:\xyz\tip\ServerJobs\ImportJobsTests\ImportJobsTests.csproj]
MSB3277: Found conflicts between different versions of "System.Diagnostics.DiagnosticSource" that could not be resolved.  These reference conflicts are listed in the build log when log verbosity is set to detailed. [C:\xyz\tip\Services\Platform\WBDataSvc\PayrollEngineDALTests\Payroll.Engine.DB.Tests.csproj]
MSB3277: Found conflicts between different versions of "System.Diagnostics.DiagnosticSource" that could not be resolved.  These reference conflicts are listed in the build log when log verbosity is set to detailed. [C:\xyz\tip\Services\Platform\WBDataSvc\PayrollEngineTests\Payroll.Engine.Tests.csproj]
MSB3277: Found conflicts between different versions of "System.Diagnostics.DiagnosticSource" that could not be resolved.  These reference conflicts are listed in the build log when log verbosity is set to detailed. [C:\xyz\tip\Services\Platform\WBDataSvc\ReportingEngineSupportTests\ReportingEngineSupportTests.csproj]
MSB3277: Found conflicts between different versions of "System.Diagnostics.DiagnosticSource" that could not be resolved.  These reference conflicts are listed in the build log when log verbosity is set to detailed. [C:\xyz\tip\Services\Platform\WBDataSvc\RuleEngineTests\RuleEngineTests.csproj]
MSB3277: Found conflicts between different versions of "System.Diagnostics.DiagnosticSource" that could not be resolved.  These reference conflicts are listed in the build log when log verbosity is set to detailed. [C:\xyz\tip\Services\Platform\WBDataSvc\WbDbTests\WbDbTests.csproj]
MSB3277: Found conflicts between different versions of "System.Diagnostics.DiagnosticSource" that could not be resolved.  These reference conflicts are listed in the build log when log verbosity is set to detailed. [C:\xyz\tip\Test\UnitTests\UnitTests.csproj]

现在果然,我们可以将丢失的绑定重定向改组到配置文件中,但是:

  1. 根据为什么控制台构建生成的 project.assets.json 与使用 VS IDE 构建生成的完全不同?这还不够好,因为 VS IDE 在 project.assets.json 中产生了一组不同的依赖项(我知道,这完全是假的。DC 中的一个问题是开放的)并且我们见证了需要不同的重定向集对于在 VS IDE 和命令行中构建的开发人员
  2. 绑定重定向单调增长 - 我们被告知何时添加,而不是何时删除。结果,随着时间的推移,我们有无数不同的绑定重定向,它们需要维护,因为有些已经过时,有些不再需要。

这是一大麻烦。

标签: .netassembly-binding-redirect

解决方案


我决定不尝试用运行时程序集解析替换配置时间绑定重定向。原因 - 我不知道如何确保它可靠地给出:

  • 不同类型的可运行项目 - 控制台应用程序、Asp.Net 应用程序、WCF 服务、单元测试项目。我们拥有它们。
  • 代码可能会产生不同的应用程序域,并且每个应用程序域都必须具有此程序集解析逻辑。我认为一般来说根本不可能。

相反,我决定利用我们设置的以下方面:

  • 我们已经对我们引用的所有 NuGet 包实施了一致的版本控制。迁移到 PackageReference 大大减少了我们可以控制的包的数量 - 因此出现了许多问题。但是我们直接引用的那些是有序的。
  • 我们现在有了 project.assets.json 文件,这些文件展示了 NuGet 包和项目引用的全貌。我们无法更改传递依赖项(就像我们可以使用 packages.config 一样),但我们可以了解所有这些。

这使得编写一个工具可以读取给定项目的 project.assets.json (并递归地读取它依赖的所有其他项目)并基于它们做两件事:

  1. 识别不同版本中提到的所有 NuGet 包依赖项。例如,如果 NuGet 包 X 依赖于 NuGet 包 Y v1,但 NuGet 包 Z 依赖于 Y v2,则 Y 是有问题的。我们可以识别这种情况并确定最高版本的文件路径 - v2。
  2. 自动更新绑定重定向。
  3. 构建完成后,将第一步中确定的文件复制到已发布的目录中。

这样,bin 文件夹中的二进制文件将不依赖于解决方案中项目的构建顺序,并且我们将有一个确定的过程来维护绑定重定向。

这是一项正在进行的工作,但看起来很有希望 - https://github.com/MarkKharitonov/GenerateDotNetBindingRedirects


推荐阅读