为啥强制降级会导致 .Net Core 中的程序集加载异常?
Posted
技术标签:
【中文标题】为啥强制降级会导致 .Net Core 中的程序集加载异常?【英文标题】:Why does a force downgrade causes an assembly load exception in .Net Core?为什么强制降级会导致 .Net Core 中的程序集加载异常? 【发布时间】:2021-12-19 11:14:39 【问题描述】:我有一个包含控制台和库项目的示例解决方案。两者都引用了相同的 nuget,但版本不同。控制台项目也有对库项目的引用。所以结构是这样的:
- Solution
- ConsoleApp
- Project Reference: Library
- Nuget: NServiceBus.RabbitMQ (5.2.0)
- Library
- Nuget: NServiceBus.RabbitMQ (6.0.0)
您可以找到解决方案here。
由于 Nuget 使用最近获胜规则,因此解析的 nuget 包是版本 5.2.0。这就是我想要的,到目前为止一切顺利。但是当我运行应用程序并运行库的方法时,我得到以下异常:
Could not load file or assembly 'NServiceBus.Transport.RabbitMQ, Version=6.0.0.0, Culture=neutral, PublicKeyToken=9fc386479f8a226c'. The located assembly's manifest definition does not match the assembly reference. (0x80131040)
在 .NET Framework 中,我将通过程序集重定向来解决这个问题。但这在 .Net Core 中不可用。我一直认为 .Net Core 通过使用 deps.json 文件自动解决了这个问题。在那里我看到以下声明:
"Library/1.0.0":
"dependencies":
"NServiceBus.RabbitMQ": "5.2.0"
,
"runtime":
"Library.dll":
但他仍然在运行时尝试解析 6.0.0 版本。我正在使用最新的 .Dot Net 3.1.X SDK。
我做错了什么还是这看起来像一个错误?
为了记录,这是一个简单的示例项目。我需要这个的实际情况要复杂得多。我也明白这样做可能会在运行应用程序时导致运行时异常。
【问题讨论】:
您确定,不同的主编号不是主要问题吗?我会尽量避免混合同一个 nuget 的主要版本。新的主要号码通常会说“我们在这里有重大变化”。 就最佳实践而言,您是绝对正确的。但有时您知道您没有调用任何具有重大更改的代码。如果你依赖一些没有匹配依赖的外部库,这个技巧在某些情况下会很方便。 【参考方案1】:这似乎是设计使然。
稍微搜索了一下,找到了这个:https://github.com/dotnet/fsharp/issues/3408#issuecomment-319466999
coreclr 将加载版本或高于参考的程序集。如果发现的程序集低于参考,则失败。
还有这个:https://github.com/dotnet/sdk/issues/384#issuecomment-260457776
.NET Core 不支持降级程序集版本
因此,为了确认,我花在查看/搜索 https://github.com/dotnet/runtime 上的时间比我预期的要多得多。最终找到了汇编版本兼容方法:https://github.com/dotnet/runtime/blob/172059af6623d04fa0468ec286ab2c240409abe3/src/coreclr/binder/assemblybindercommon.cpp#L49-L53
它分别检查版本的所有组件,但如果我们只看一个,我们可以看到它在做什么:
if (!pFoundVersion->HasMajor() || pRequestedVersion->GetMajor() > pFoundVersion->GetMajor())
// - A specific requested version component does not match an unspecified value for the same component in
// the found version, regardless of lesser-order version components
// - Or, the requested version is greater than the found version
return false;
正如评论所说,如果程序集的版本低于请求的版本,加载程序将拒绝该程序集。在您的情况下,假设程序集版本与包版本匹配(它不必),您的库正在请求版本 6.0.0,但程序集加载器/绑定器在磁盘上找到版本 5.2.0,该版本较低.因此,它拒绝该 dll,继续查找,但在探测路径上找不到合适的程序集版本,并最终引发 FileLoadException。
我不清楚的是,是否仅在默认程序集加载器上检查此程序集兼容性,或者即使您将自己的事件处理程序添加到 AssemblyLoadContext.Default.Resolving。您可以尝试添加自己的处理程序,当它请求更高版本的程序集时,您无论如何都会返回较低版本的程序集。这可能是解决问题的一种方法。
【讨论】:
非常感谢您的回答!我在谷歌上找不到任何关于它的信息。我想我应该开始在 GitHub 上搜索更多内容。对我们来说,很遗憾 .Net Core 不再支持它。这是我们在开发框架库时必须考虑的事情。如果我们增加一个依赖版本,这意味着使用该框架的每个人都必须遵循。如果严格遵循 semver 版本控制,这是一件好事,但是很多库不包含对主要版本的重大更改。所以在这些情况下,它的灵活性较差。以上是关于为啥强制降级会导致 .Net Core 中的程序集加载异常?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 .Net 4.0 构建客户端 DataContracts 会导致 .Net 4.5 应用程序中的 MethodAccessException?
为啥将返回类型添加到 void 返回方法会导致 MissingMethodException
为啥 Gradle 会降级 Grails 3.1 应用程序中的传递依赖项?