Cannot Load Assemblies For .Net Standard library (System.Text.Json)

12

I am writing a .Net Standard 2.0 library that will be used by a binary PowerShell module. The library will be basically an API client with a lot of classes for dealing with the JSON responses. Prior to trying to deserialise the strings, I confirmed that the API was providing the JSON encoded string without issue.

As it was compatible with .Net Standard 2.0 when using the NuGet package, I thought I would try switching to System.Text.Json, rather than using NewtonSoft. However, it does not seem to have the version of particular assemblies it requires on certain platforms.

My Environment:

Windows 10
PowerShell 5.1 Desktop
.Net Framework 4.8
PowerShell Core 6.2.2
dotnet version 3.0.100

On PowerShell Desktop, I get the following problems when it has to deserialise anything:

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

On PowerShell Core there the same exception for another assembly/file.

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

Anyone got any advice on how I can resolve this without switching to Newtonsoft's JSON package? Falling back from System.Text.Json 4.7.1 to 4.7.0 or 4.6.0 introduces problems with other assemblies that are part of the NuGet package for System.Text.Json. I have read the advice here, but I either can't apply it here, or I simply do not understand.

Thanks in advance. Please let me know if you require more information, I will provide it.

EDIT

I updated the csproj as suggested by Gokhan

<PropertyGroup>
  <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
  <GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
</PropertyGroup>

This generated the following code in the 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>

So the auto-generation of all the binding redirects is not working, as mentioned above there are at least two more that do not work. I would try manually creating them, but as far as I am aware, there is no source config file to put them in now. If anyone has any direction on that, I would appreciate it.

c#
.net-standard
.net-standard-2.0
system.text.json
asked on Stack Overflow Feb 27, 2020 by Ash • edited Mar 2, 2020 by Ash

3 Answers

8

The problem you are hitting is because your library is targeting .NET Standard, which is not a runnable framework, so it sometimes has problems when trying to load it using models like the one Powershell does. Let me try to explain a bit more what is going on.

.NET Standard is simply an API surface area Spec, so basically just a set of APIs that will be guaranteed to be present and to be able to run on any runnable framework that implements that version of .NET Standard. What this means, is that if you have a library that targets .NET Standard, there is no real way to publish that library with all of its dependencies in a way guaranteed to run on any runnable framework, because each runnable framework might require additional dependencies for your library to load correctly. When referencing a .NET Standard library from a console application (either via Project reference or via a NuGet package) the console application will know which runnable framework its targeting, so it will be able to grab the right set of dependencies that your library will need at runtime, but the problem with your scenario is that this console app doesn't really exist, since you are loading it from powershell (which in a sense is basically the console app). Because of all of this, in order to have your library load successfully at runtime you will have to perform the work that a console app referencing your library would do, and pick the right references to carry along your library depending on the runtime that will be loading it. For powershell, there are basically two possible runtimes (.NET Core for powershell core, and .NET Framework for Powershell).

The easiest way to solve your problem, is to just create one dummy console app: from command prompt simply run dotnet new console -n dummyConsoleApp, set the targetframework to netcoreapp2.0 (assuming you are running on powershell core, if you are instead running on full powershell then set it to net46). Then add a project reference to your library like <ProjectReference Include="...<FullPathtoYourProject>\File.csproj" /> and then run from the command prompt dotnet publish -r win-x64 which should create a publish directory inside your bin folder which will have all of the assemblies that your application will use at runtime. After that, try loading your File.dll again, but this time from that publish folder, and you should be successful this time, since that publish folder will have all the right dependencies you will need for the runtime that powershell is running on. If for whatever reason this doesn't work for you, please feel free to log an issue about this in https://github.com/dotnet/runtime repo and tag me (@joperezr) and I'll gladly help you diagnose and fix the issue.

0

If you can't find the cause of version conflict for System.Buffers DLL, I think you can use assemblybinding in your config file to use version 4.0.3.0 instead of 4.0.2.0

<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>

If you have other version conflicts then delete all dependentassembly tags in the config file(including the one above) and add this to the project (.csproj) file:

<PropertyGroup>
  <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
  <GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
</PropertyGroup>

When you build your project, you'll see (WebAppName).dll.config file in the output bin folder. Copy all assemblybindings from there to your source config file. Then delete the above code part from the project file.

answered on Stack Overflow Feb 27, 2020 by Gokhan • edited Mar 1, 2020 by Fred
0

Open your solution in Visual studio.Check your reference for all dlls. Do you have duplicate dll one from Bin and other from nugget package? If you have Visual Studio 2017 version 15.7 or later, you can easily disable autogenerated binding redirects in the project's property pages.

Right-click the project in Solution Explorer and select Properties.

On the Application page, uncheck the Auto-generate binding redirects option.

Press Ctrl+S to save the change. Try building it. Check that you are referencing all Dlls from nugget location and nothing is from bin folder. If it build you are good to go otherwise do binding redirect compile again.

answered on Stack Overflow Mar 3, 2020 by Jin Thakur

User contributions licensed under CC BY-SA 3.0