Consuming netstandard13 packages from Xamarin projects - c#

I'm trying to make Npgsql, the PostgreSQL provider for .NET, available for consumption by Xamarin users. Npgsql already supports the .NET Platform Standard (version 3), and the documentation on the standard contains the following sentence:
If a library targets .NET Platform Standard version 1.3, it can only run on .NET Framework 4.6 or later, .NET Core, Universal Windows Platform 10 (UWP), and Mono/Xamarin platforms.
I can successfully install the Npgsql nuget from my Xamarin.Android project. However, when I try to build I get the following error:
System.IO.FileNotFoundException: Could not load assembly 'System.Security.Cryptography.Algorithms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. Perhaps it doesn't exist in the Mono for Android profile?
Now, that packages (like many RC2 packages Npgsql depends on) has a lib/MonoAndroid10 directory containing . (also the same in ref), which seems to indicate that the package is supported on Mono.Android, but no DLL is necessary (since the logic is part of the framework). That's great, but the Xamarin.Android build process includes a ResolveAssemblies task, which walks the DLL dependency graph (this is the relevant code). Since Npgsql's netstandard13 DLL references System.Security.Cryptography.Algorthims.dll, this fails.
I'm confused that the nuget declares "it's all good", while the build process itself seems obviously incompatible with consuming netstandard13 dependencies.
Any ideas?

Related

Azure Function can't find a file/dll that it suppose to use

I have an azure webjob that used to work well. When I added an internal nuget of the company I work for and used it, I received the following error:
Could not load file or assembly 'System.Threading.Tasks.Dataflow, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.
The weird thing is that both the interal nuget, and a nuget that was defualtly existed in that project before, are using the System.Threading.Tasks.Dataflow, Version=5.0.0.0
When .NET was first created, the Windows-only .NET Framework, it has a concept called "strong naming" which makes the assembly version part of the assembly identity (not just the name, but also includes public key). With the .NET Framework when A.dll has a reference to B.dll, at runtime the version of B.dll must match the version A.dll was compiled against. The way to work around that was to use a binding redirect in an app.config or web.config file.
With .NET Core, they stopped enforcing this, but they still put in a check to make sure that the assembly found on disk is a HIGHER version than what the compile time reference was.
This is relevant because you're using Microsoft.NET.Sdk.Functions version 3.0.13, which targets .NET 3.1. Therefore, I assume you're Azure Functions app is running on .NET Core 3.1. I don't know what the assembly version of System.Threading.Tasks.Dataflow that ships in the .NET 3.1 runtime is, but I'd expect it to be version 3.something.
While NuGet package versions do not have to match assembly versions, it is very often the case that the major (and sometimes minor) versions do match, especially for System.* packages/assemblies.
Putting 2+2 together, you're running on .NET Core 3.1, which has System.Threading.Tasks.Dataflow.dll version 3.something, but your something.Kafka.dll assembly is compiled against System.Threading.Tasks.Dataflow.dll version 5.something. Since the compile time reference is a higher version of the version available at runtime, the .NET assembly loader refuses to use it.
There are two actionable things now.
Firstly, you can do one of three things to fix your project. Use a newer version of Azure Functions that targets .NET 5 or higher. Alternatively, use an older version of your whatever.Kafka package that doesn't depend on BCL (base class library) assemblies that are higher version than the .NET Core 3.1 runtime provides. Finally, I'm guessing the reason the dll doesn't exist in your project's bin directory is because of this issue: https://github.com/Azure/azure-functions-host/issues/5894
Secondly, contact the package owners of this Kafka package, and inform them that they don't need to use the Dataflow NuGet package. .NET Core 1.0 had it built into the BCL, so the package is only needed for .NET Standard and .NET Framework projects. If this Kafka package does support .NET Framework or .NET Standard, then if they change their PackageReference to include Condition=" '$(TargetFrameworkIdentifier) != '.NETCoreApp' ", then the package will be used only in .NET Framework and .NET Standard, and the BCL version of the package will be used for .NET Core and .NET 5 and above. If they use any other System.* package (that ships in the runtime), they should do the same. Of course, if the package owner refuses to remove Dataflow as a package dependency, or if there are other packages that bring in Dataflow as a transitive package, then you're stuck. But by informing the Kafka package owners of this, they at least have the opportunity to improve their package.

Where did all the assemblies go ? .NET 5.0 error CS1069

So my code which worked fine yesterday, screwed up when I added a .net 5.0 class library project to my solution.
Error CS1069 The type name 'Bitmap' could not be found in the namespace 'System.Drawing'. This type has been forwarded to assembly 'System.Drawing.Common, Version=0.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' Consider adding a reference to that assembly.
There is just one problem, when i look at what replaced "References" it now says "Dependencies" and when I try to add a dependency, "Add reference" is gone and there are no more .net assemblies being shown except under COM projects and type libs and when I add system.drawing etc, the error still remains and the code remains unreadable.
There are multiple reasons for what you're experiencing, I'll try to explain with a variety of assorted (and unordered) bullet-points:
Why isn't System.Drawing in .NET Core?
".NET 5" is the next iteration of .NET Core 3.1, not the .NET Framework 4.8 (.NET 5 comes immediately after .NET Core 3.1, there was never was a ".NET Core 4" to avoid confusion with .NET Framework 4).
.NET Core (including .NET 5) is designed to be cross-platform (i.e. to support Windows, Linux, macOS) with a single runtime.
Whereas previously people had to target .NET Framework for Windows, and target Mono, Xamarin, Unity, UWP, Silverlight, etc - which made multi-platform development in C# a pain.
Note that while Windows, Linux, and macOS now all share the real McCoy .NET 5 (and Silverlight is dead), other platforms like Xamarin, Unity, Mono, and UWP still have their own separate implementations of .NET (CLR+BCL) hence the need for ".NET Standard". At least we don't need those weird "Shared Projects" and "Portable Framework" projects anymore, phew!
In the .NET Framework, the System.Drawing API is just a .NET wrapper over Win32's GDI/GDI+, which means it's not cross-platform.
While System.Drawing seems like a platform-independent API, if you look closely at public types and methods like Graphics, Brush, Bitmap, Image and so on you'll see that they're all just thin wrappers and leaky-abstractions over GDI+. Mono does have System.Drawing reimplemented for Linux, however they did it by reimplementing GDIPLUS.dll which is about as horrible as it sounds.
So because System.Drawing is not cross-platform it was removed from .NET Core's "in-box" API.
So now you're wondering how you can get System.Drawing in .NET Core...
How can I get System.Drawing in .NET Core?
Earlier questions asked on StackOverflow from when .NET Core was more anaemic (and not yet pitched as a replacement for .NET Framework 4) have suggested switching to completely different and incompatible (but cross-platform-by-design) library, such as ImageSharp or ImageProcessor, however a better solution for Windows-only applications exists: the official Microsoft Windows Compatibility Pack (note that the aforementioned blog article is from 2017; as of 2021 the Windows Compatibility Pack is pretty-much fully implemented now).
All you need to do is open the NuGet package manager built-in to Visual Studio and add Microsoft.Windows.Compatibility as a package-reference and magically System.Drawing will be available for use in your application. You can also access the NuGet package manager via the Dependencies context-menu in Solution Explorer.
If you're using the .NET CLI ("command-line interface", not the "common language infrastructure", hurrah for overloaded acronyms) then just run dotnet add package Microsoft.Windows.Compatibility.
But why can't I add assembly references in .NET Core like I used to in .NET Framework?
You can!. It's just that (as of April 2021, running Visual Studio 2019 16.9) the UI for adding an assembly reference is kinda horrible.
You can do it manually by editing your .csproj and adding a <Reference Include="pathToDll.dll" /> (in the same <ItemGroup> as the other references).
You can do it from within Visual Studio by ignoring the missing menu option and using the Add Project Reference dialog:
Follow these steps
Go Solution Explorer > Your Project > Dependencies > Add Project Reference.
In the popup dialog, choose the Browse tab:
Then click the Browse... button:
Then browse for your target assembly DLL:
Voila - the added assembly reference will appear under a new Assemblies node under Dependencies:
Do note that (generally speaking, there are exceptions) you can only reference assembly DLLs that target .NET Core or .NET Standard. Because most DLLs built for .NET Core and .NET Standard exist as NuGet packages anyway there isn't much need to add an assembly reference directly.
Microsoft seems to have migrated Add Reference to standard SDK assemblies to "Manage NuGet Packages".. a step I do not understand the point of since the correct assembly is mixed in with third party user contributed search results.
Simply click where references would have been and is now dependencies, and right-click and then click Manage Nuget Packages, do a search for the assembly and VERIFY that Microsoft published it and it meets the .net Core requirements.
Yeah they dropped the ball on this in my humble opinion. Took me a minute to figure out that standard assemblies do not appear to be installed on the system.
The package gets installed under your user account's home directory, not in a system-wide folder requiring elevated user permissions to access the dll, so if your account is bugged, you get to a nice infected copy of the assembly each and every time :)

UWP app not able to resolve .NET Standard 2.0 assembly

I have a UWP app and in one of the referenced projects the serial port is getting used. So I made that project a .NET Standard 2.0 project. The UWP app was changed to Target Windows 10 Fall Creators Update (10.0;Build 16299)
As per the compatibility chart it should have worked. But I am getting compilation error
Cannot resolve Assembly or Windows Metadata file 'Type universe cannot resolve assembly: netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51.'
I am not sure what is going wrong.
In my case it was an outdated version of the Microsoft.NETCore.UniversalWindowsPlatform nuget that was causing this problem.
Try setting not only the Target but also the Minimum version to Fall Creators Update.
When creating a UWP app in Microsoft Visual Studio, you can choose which version to target. Projects using .NET Standard 2.0 must have a Minimum Version of Build 16299 or later.
[docs]

'Could not load file or assembly 'netstandard, Version=2.0.0.0, ...'. Reference assemblies should not be loaded for execution

Goal:
From a .NET 4.7 console app, using reflection with Assembly.GetType(), I am trying extract the Type of a netstandard 2.0 class from Assembly X. Then I want to create an instance of this Type with Activator.CreateInstance().
What I am trying to do:
However, this assembly X has a dependency to netstandard 2.0. To be able to get the Type, netstandard dependency has to be loaded into the AppDomain. That's why when the AppDomain is requesting the netstandard assembly through the AssemblyResolve event, I simply load the dll like this :
var netStandardDllPath = #"C:\Users\xxx\.nuget\packages\NETStandard.Library.2.0.0-preview1-25301-01\build\netstandard2.0\ref\netstandard.dll";
return Assembly.LoadFrom(netStandardDllPath);
Which throws:
System.BadImageFormatException: 'Could not load file or assembly
'file:///C:\Users\vincent.lerouvillois.nuget\packages\NETStandard.Library.2.0.0-preview1-25301-01\build\netstandard2.0\ref\netstandard.dll'
or one of its dependencies. Reference assemblies should not be loaded
for execution. They can only be loaded in the Reflection-only loader
context. (Exception from HRESULT: 0x80131058)'
Inner Exception: BadImageFormatException: Cannot load a reference
assembly for execution.
What I know:
I know that they want us to load the DLL with Assembly.ReflectionOnlyLoadFrom. But doing that will prevent me from instanciate the type with Activator.CreateInstance(). See Microsoft official post
Also, I tried referencing the Nuget packages NETStandard.Library 2.0.0-preview1-25301-01 and NETStandard.Library.NETFramework 2.0.0-preview1-25305-02 in my console app so it would have the netstandard 2.0 libraries referenced, but it didn't change anything.
Question:
Does anyone would know if there is a proper way to load that dll without error, or maybe if this is a bug, or else? Or why this kind of dll is not able to load for execution?
The netstandard.dll you are trying to load is a reference assembly that which cannot be loaded for runtime on .NET Framework as pointed out by others. However if you need to resolve that dependency you will need to runtime version that maps to the framework you are trying to run on.
For .NET Standard support we are including them as part of the msbuild extensions that ship with VS so you will want to get the version of netstandard.dll from there. Depending on which version of VS2017 you have installed it should be somewhere like C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\netstandard.dll or from the .NET Core 2.0 SDK you can find it C:\Program Files\dotnet\sdk\2.0.0\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\netstandard.dll
Try using one of those versions in your scenario.
Wow. I just spent several hours tracking the cause of this "could not load ... netstandard" error down.
For me, the problem was that my .NET Framework project (which references both .NET Framework and .NET Standard libraries) was built with .NET Framework 4.7.2 and the system where I was deploying and running it did not have 4.7.2 installed.
Deploying a very small Console project with the same basic structure and references and executing that in a Command window finally revealed the correct error, in a pop-up, that .NET Framework 4.7.2 was missing.
If you're struggling with this particular error, make sure you have the necessary .NET Framework installed.
Set Copy Local to true in netstandard.dll properties.
Open Solution Explorer and right click on netstandard.dll.
Set Copy Local to true.
You can't load a reference assembly.
.NET Standard is a collection of APIs that must be provided by .NET Standard compatible implementations.
A reference assembly only contains contracts. This means that it contains no implementation. The assembly you are trying to load contains the .NET Standard 2.0 contracts.
A contract looks like this: https://github.com/dotnet/standard/blob/master/netstandard/ref/mscorlib.cs
EDIT: .NET Framework 4.7 implements .NET Standard 2.0, so you shouldn't need to load any assembly to use Activator.CreateInstance() to instantiate a .NET Standard type.
NETStandard 2.0.0-preview1 in not compatibility with net461 and net47.
but for realese .NET Core SDK 2.0 assemblies (as well as 2.0.0-preview2)
var netStandardDllPath = #"c:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.netcore.app\2.0.0\ref\netcoreapp2.0\netstandard.dll";
Console.WriteLine(Assembly.LoadFrom(netStandardDllPath).FullName);
all is ok.
But if you steel need to load preview1 libraries, maybe you should to use netstandard2.0 instead net471.
For me solved doing the following:
1 - Installed latest .Net Framework on server.
2 - Updated windows server and my local machine.
3 - Went to Manage Nuget Package and updated all references on the update tab.
Perhaps only doing step 3 can solve in your case
In case if IBM Message Queue references are used in the project solution, this exception indicates that the DLL used for refering MQ classes are incompatible with the host(server) .NET version installed.
In this scenario, either we need to update server with latest update and make sure .NET latest version is available or use lower version of IBM Message queue DLL as reference.
Old version DLL - amqmdnet.dll (no new features will be introduced by IBM as not in support)
Latest version DLL - amqmdnetstd.dll (to run IBM MQ classes for .NET Standard, you must install Microsoft .NET Core)
Install NetStandard.Library 2.0.0.0 from NuGet , It works for me. when I downgrade .net framework 4.6.1 to 4.6.0
If you are having this issue for a project that used to work, try deleting the bin and obj folders since caching can cause this, too.

When using .Net Standard 1.4 in a library and .Net framework 4.6.1 in and application, unable to load file System.IO.FileSystem, Version=4.0.1.0

I have a solution that contains a library and 2 applications. The applications represent the same program, with one built to target the Windows App Store through UAP10 and the other built to target a Microsoft Windows PC using .Net Framework 4.6.1. I'm using Visual Studio 2017.
I set the library project target .Net standard 1.4.
I set the UWP application to target Windows 10 Aniversary Edition (10.0; Build 14393), Min version Windows 10 (10.0; Build 10586).
I set the generic Windows application to target .Net Framework 4.6.1.
The UWP version compiles and runs fine.
Initially, the .Net Framework 4.6.1 compiles and runs. However, when I make a call to File.Open from System.IO, I get the following error message:
System.IO.FileNotFoundException: 'Could not load file or assembly
'System.IO.FileSystem, Version=4.0.1.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The
system cannot find the file specified.'
The code block with File.Run is within the library code (.Net Standard 1.4). I'm not sure what is causing the problem. I thought that I could use .Net Standard 1.4 libraries within an application that references .Net Framework 4.6.1.
As a workaround, I tried installing the Nuget package for System.IO in the .Net Framework application. System.IO Version 4.0.1.0 is not even an option. There is a version 4.0.10, but it doesn't work when this Nuget package is installed.
So, how do I properly reference System.IO operations within a .Net Framework 4.6.1 application that references the System.IO code within a .Net Standard 1.4 library?
This usually happens with "classic" csproj projects when referenced projects require overwritten override system defined types but no binding redirects are present that set this up correctly. When installing all the packages into a .net framework app (e.g. NETStandard.Library or NETStandard.Library.NETFramework(for upcoming .NET Standard 2.0)), this should be done automatically.
To force generation of binding redirects, add this to the csproj file of the .NET Framework project (if it is an executable project, the second property should be irrelevant but it doesn't hurt):
<PropertyGroup>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
</PropertyGroup>

Categories