无法加载 .Net Standard 库(System.Text.Json)的程序集

17
我正在编写一个.NET Standard 2.0库,将被二进制PowerShell模块使用。该库基本上将是一个API客户端,其中包含许多用于处理JSON响应的类。在尝试反序列化字符串之前,我确认API在不出问题的情况下提供了JSON编码的字符串。
因为在使用NuGet包时它.NET Standard 2.0兼容,所以我想尝试切换到System.Text.Json,而不是使用NewtonSoft。但是,在某些平台上,它似乎没有特定程序集所需的版本。
我的环境: Windows 10 PowerShell 5.1桌面版 .NET Framework 4.8 PowerShell Core 6.2.2 dotnet版本3.0.100
在PowerShell Desktop上,当它必须反序列化任何内容时,我会遇到以下问题:
PS dir:\> Import-Module '.\file.dll'
PS dir:\> [namespace.class]::TestMethod($string, $anotherString)  # Test method to return string
{"attribute":"value"}
PS dir:\> [namespace.class]::Method($string, $anotherString)  # Same as above, but uses System.Text.Json to deserialise
Could not load file or assembly 'System.Buffers, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' or one of its dependencies. The system
cannot find the file specified.

# System.Buffers.dll is with the System.Text.Json package, but seems to be the wrong version
PS dir:\> (Get-Item .\System.Buffers.dll).VersionInfo.FileVersion
4.6.26515.06
PS dir:\> [System.Reflection.Assembly]::LoadFile("$pwd\System.Buffers.dll").GetName().Version

Major  Minor  Build  Revision
-----  -----  -----  --------
4      0      3      0

在PowerShell Core中,对于另一个程序集/文件也存在相同的异常。
PS dir:\> Import-Module '.\file.dll'
PS dir:\> [namespace.class]::Method($string, $anotherString)
"Could not load file or assembly 'System.Text.Encodings.Web, Version=4.0.5.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. Could not find or load a specific file. (Exception from HRESULT: 0x80131621)"

#System.Text.Encodings.Web.dll is with the System.Text.Json package and appears to be the required version...
PS dir:\> (Get-Item .\System.Text.Encodings.Web.dll).VersionInfo.FileVersion
4.700.19.56404
[System.Reflection.Assembly]::LoadFile("$pwd\System.Text.Encodings.Web.dll").GetName().Version

Major  Minor  Build  Revision
-----  -----  -----  --------
4      0      5      0

有没有人能给我一些建议,让我不用切换到Newtonsoft的JSON包就能解决这个问题?从System.Text.Json 4.7.1回退到4.7.0或4.6.0会引入与NuGet包中System.Text.Json的其他程序集相关的问题。我已经在这里读到了建议,但要么我无法在这里应用它,要么我根本不理解。
提前感谢您的帮助。如果需要更多信息,请告诉我,我会提供。
编辑:
我按照Gokhan的建议更新了csproj。
<PropertyGroup>
  <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
  <GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
</PropertyGroup>

这将在appName.dll.config文件中生成以下代码

<runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.0.6.0" newVersion="4.0.6.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>

所以自动生成所有绑定重定向并不起作用,如上所述,至少还有两个不起作用。我会尝试手动创建它们,但据我所知,现在没有源配置文件可放置它们。如果有人对此有任何指导,我将不胜感激。
3个回答

15
你遇到的问题是因为你的库针对的是 .NET Standard,它不是一个可运行的框架,因此在尝试使用像 Powershell 这样的模型加载时会有一些问题。让我再解释一下是怎么回事。

.NET Standard 是一个API表面规范,基本上只是一组API,保证它们存在并能在实现该版本的.NET Standard的任何可运行框架上运行。这意味着,如果您有一个针对.NET Standard的库,没有真正的方法来以保证在任何可运行框架上运行的方式发布该库及其所有依赖项,因为每个可运行框架可能需要其他依赖项才能正确加载您的库。当从控制台应用程序(通过项目引用或NuGet包)引用.NET Standard库时,控制台应用程序会知道其定位的可运行框架,因此它将能够在运行时获取您的库所需的正确依赖项集,但您的情况存在问题,因为这个控制台应用程序实际上不存在,因为您正在从PowerShell中加载它(从某种意义上说,PowerShell基本上就是控制台应用程序)。因此,在运行时成功加载库,您必须执行控制台应用程序引用您的库会执行的工作,并根据将要加载它的运行时选择正确的引用项。对于PowerShell,基本上有两个可能的运行时(.NET Core用于PowerShell Core,.NET Framework用于PowerShell)。

最简单的解决方法是创建一个虚拟控制台应用程序:从命令提示符中运行 dotnet new console -n dummyConsoleApp,将目标框架设置为netcoreapp2.0(假设您正在运行 PowerShell Core,如果您正在运行完整版 PowerShell,则将其设置为net46)。然后添加项目引用到您的库,如<ProjectReference Include="...<FullPathtoYourProject>\File.csproj" />,然后从命令提示符运行dotnet publish -r win-x64,这将创建一个发布目录,位于您的 bin 文件夹中,其中包含应用程序在运行时将使用的所有程序集。之后,尝试再次从该发布文件夹加载您的 File.dll,此时您应该能够成功运行,因为该发布文件夹具有PowerShell正在运行的运行时所需的所有正确依赖项。如果出现任何问题,请随时在https://github.com/dotnet/runtime仓库中记录问题,并标记我(@joperezr),我会乐意帮助您诊断和解决问题。

嗨,Jose。非常感谢您对此问题的详细回答。这确实有所帮助。我想我还是有点困惑于.NET Standard的东西。如果我回退到目标net472或更低版本,我是否仍然可以使用PowerShellStandard.Library包,以便库可以在PowerShell桌面版和核心版上运行?如果它需要在两个运行时上运行,是否需要为两个运行时发布dlls?我有另一个模块,它针对4.7.2与PowerShell 5库,跨平台运行良好,但不知道我是否只是“幸运”。如果我还是没有理解,请原谅。 - Ash
我试图遵循这里的建议(https://devblogs.microsoft.com/powershell/powershell-standard-library-build-single-module-that-works-across-windows-powershell-and-powershell-core/)关于模块的问题。看起来他们也针对.NET Standard 2.0进行了目标设置。 - Ash
哦,有趣的是,我之前从未使用过 PowerShellStandard.Library,它非常有趣,甚至还有自己的模板。所以回答你的问题,如果你创建一个针对 net472 或 netcoreapp2.0(或同时针对两者)的项目,你仍然可以使用 PowerShellStandard.Library,因为该包针对的是.NETStandard 2.0,在这两个地方都得到了支持。如果您正在使用他们的模板来创建您的模块,请设置属性<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>,然后通过运行来创建两个发布目录: - Jose Perez Rodriguez
dotnet publish -f netcoreapp2.0dotnet publish -f net461。这将创建两个单独的发布目录,一个用于每个框架。然后,在从完整 PowerShell 运行时从 net461 文件夹加载您的模块,在从 PowerShell Core 运行时从 netcoreapp2.0 文件夹加载。这样应该可以使两种情况都能正常工作,同时只保留一个代码库。 - Jose Perez Rodriguez
Jose,感谢您回复我。这真的很有帮助。 - Ash
1
很高兴能够帮忙,如果您有任何后续问题或困难,请随时联系我。 (我不总是检查我的stackoverflow收件箱:P,但如果您在Github的运行时存储库中引用我,我会立即回复) - Jose Perez Rodriguez

2
如果您无法找到 System.Buffers DLL 版本冲突的原因,您可以在配置文件中使用 assemblybinding 来使用 4.0.3.0 版本代替 4.0.2.0 版本。请注意保留 HTML 标签。
<runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51"/>
        <bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
      </dependentAssembly>
    </assemblyBinding>
 </runtime>

如果您遇到其他版本冲突,则请在配置文件中删除所有dependentassembly标记(包括上面的标记),并将以下内容添加到项目(.csproj)文件中:
<PropertyGroup>
  <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
  <GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
</PropertyGroup>

在构建项目时,你会在输出的bin文件夹中看到(WebAppName).dll.config文件。将其中所有的assemblybindings复制到你的源配置文件中。然后从项目文件中删除上述代码部分。


嗨,Gokhan,感谢您的回答。在我的dll.config文件中,它已为System.Runtime.CompilerServices.Unsafe生成了一个绑定重定向,但没有其他的。您所提到的源配置是指哪个?据我所知,.Net Standard项目没有配置文件,至少我没有看到过。 - Ash

0

在 Visual Studio 中打开您的解决方案。检查所有 dll 的引用。您是否有重复的 dll,一个来自 Bin 文件夹,另一个来自 nugget 包?

如果您使用的是 Visual Studio 2017 版本 15.7 或更高版本,则可以轻松地在项目属性页面中禁用自动生成的绑定重定向。

在“解决方案资源管理器”中右键单击项目,然后选择“属性”。

在“应用程序”页面上,取消选中“自动生成绑定重定向”选项。

按 Ctrl+S 保存更改。尝试构建它。

检查您是否从 nugget 位置引用了所有 Dll,而没有从 bin 文件夹引用任何内容。

如果构建成功,则一切正常;否则,请重新进行绑定重定向编译。


问题从来不是构建。它总是成功构建,但抱怨使用的依赖关系。很遗憾,这里没有我没有尝试过的东西。 - Ash

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接