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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With