为什么强制降级会导致.Net Core 程序集加载异常?
Why does a force downgrade causes an assembly load exception in .Net Core?
我有一个带有控制台和库项目的示例解决方案。两者都引用相同的 nuget 但版本不同。控制台项目还引用了库项目。所以结构是这样的:
- Solution
- ConsoleApp
- Project Reference: Library
- Nuget: NServiceBus.RabbitMQ (5.2.0)
- Library
- Nuget: NServiceBus.RabbitMQ (6.0.0)
您可以找到解决方案 here。
由于 Nuget 使用最近的 wins 规则,因此解析的 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。
我是不是做错了什么,或者这看起来像是一个错误?
郑重声明,这是一个简单的示例项目。我需要这个的实际情况要复杂得多。我也明白这样做会导致 运行 时间异常,同时 运行 应用程序。
这似乎是设计使然。
稍微搜索了一下,我发现了这个:https://github.com/dotnet/fsharp/issues/3408#issuecomment-319466999
The coreclr will load an assembly of the version or higher than the reference. If the assembly discovered is lower than the reference then it fails.
还有这个:https://github.com/dotnet/sdk/issues/384#issuecomment-260457776
downgrading the assembly version isn't supported on .NET Core
因此,确认一下,我在 looking/searching 到 https://github.com/dotnet/runtime. Eventually I found the assembly version compatibility method: 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,但程序集 loader/binder 在磁盘上找到版本 5.2.0,这较低。因此,它拒绝该 dll,继续寻找,但随后无法在探测路径上找到合适版本的程序集并最终抛出 FileLoadException。
我不清楚是否仅在默认程序集加载器上检查此程序集兼容性,或者即使您将自己的事件处理程序添加到 AssemblyLoadContext.Default.Resolving。您可以尝试添加自己的处理程序,当它请求更高版本的程序集时,您仍然 return 较低版本的程序集。这可能是解决此问题的一种方法。
我有一个带有控制台和库项目的示例解决方案。两者都引用相同的 nuget 但版本不同。控制台项目还引用了库项目。所以结构是这样的:
- Solution
- ConsoleApp
- Project Reference: Library
- Nuget: NServiceBus.RabbitMQ (5.2.0)
- Library
- Nuget: NServiceBus.RabbitMQ (6.0.0)
您可以找到解决方案 here。
由于 Nuget 使用最近的 wins 规则,因此解析的 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。
我是不是做错了什么,或者这看起来像是一个错误?
郑重声明,这是一个简单的示例项目。我需要这个的实际情况要复杂得多。我也明白这样做会导致 运行 时间异常,同时 运行 应用程序。
这似乎是设计使然。
稍微搜索了一下,我发现了这个:https://github.com/dotnet/fsharp/issues/3408#issuecomment-319466999
The coreclr will load an assembly of the version or higher than the reference. If the assembly discovered is lower than the reference then it fails.
还有这个:https://github.com/dotnet/sdk/issues/384#issuecomment-260457776
downgrading the assembly version isn't supported on .NET Core
因此,确认一下,我在 looking/searching 到 https://github.com/dotnet/runtime. Eventually I found the assembly version compatibility method: 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,但程序集 loader/binder 在磁盘上找到版本 5.2.0,这较低。因此,它拒绝该 dll,继续寻找,但随后无法在探测路径上找到合适版本的程序集并最终抛出 FileLoadException。
我不清楚是否仅在默认程序集加载器上检查此程序集兼容性,或者即使您将自己的事件处理程序添加到 AssemblyLoadContext.Default.Resolving。您可以尝试添加自己的处理程序,当它请求更高版本的程序集时,您仍然 return 较低版本的程序集。这可能是解决此问题的一种方法。