Nuget PCL library conflict - c#

I'm using Nito.Async both in a PCL framework library and in client app which uses the library. The PCL lib targets .Net4.5 & SL5, and the client is .Net4.5.
If I don't reference Nito.Async in client app, everything is fine. But if I reference it, when i run the app, an MissingMethodException occurs :
Method not found: 'Microsoft.Runtime.CompilerServices.TaskAwaiter`1<!0> Nito.AsyncEx.AwaitableDisposable`1.GetAwaiter()'
After digging a little more, it seems the problem is msbuild copy the Nito lib from portable-net40 referenced by the PCL lib in the target \bin folder, and then, copy the Nito lib from net45 referenced by the client in the target \bin. So it overwrites the first portable Nito.Async DLL... And when I launch the app, the portable-net40 is replaced by the net45.
The only few options I see are :
Directly include Nito.Async source in my library, but it means loosing the Nuget advantage of having up-to-date libs...
Ask Stephen Cleary to rename his DLL for .Net45 target to something like Nito.AsyncEx.Net45.dll instead of Nito.AsyncEx.dll (and do it for each distinct target), but I doubt it's a perfect solution.
How can I handle this kind of DLL conflict ?
Is there something on the Nuget or MsBuild side already made for this kind of problem ?

The portable version is supposed to be replaced by the net45 version in this case. The MissingMethodException you get means that there's an API compatibility bug in the Nito.AsyncEx package.
Looking at the source code, I'm not sure there's a way to fix this. GetAwaiter() returns a TaskAwaiter<T>, but that type has a different identity (it's in a different namespace) for portable libraries targeting Silverlight or .NET 4. I think this was necessary because the constructor is internal so we had to reimplement the class for the portable async support for platforms that didn't have it already.
The simplest fix for this would be to drop support for any platforms which don't already support async from the PCL. So you could target .NET 4.5, WP8, WP8.1, and Windows 8 store apps.

Related

To which Project should LibVLC dependencies be added?

I have a Solution with .NET Framework Project A which builds a winforms application containing a class, MyPlayer which requires LibVLCSharp. In order for the application to build and run correctly I had to add the following Nuget packages:
LibVLCSharp
LibVLCSharp.WinForms
VideoLAN.LibVLC.Windows
Now I want to move class MyPlayer to a separate .NET Standard class library, Project B, to separate out function from UI and so that it can be used by multiple other projects targeted to different platforms. In order for B to compile I only had to add the LibVLCSharp Nuget package. Then I set B as a Reference for A.
Obviously, Project A is going to require the other two Nuget packages somehow, but I am unsure to which project it is most appropriate to add them. What makes the most sense in this situation? Or is there really only one way it would work?
that's a good question, and I don't know if it is properly documented on LibVLCSharp.
Short Answer:
LibVLC must always be referenced on the executable project (A)
WinForms isn't compatible with .net standard, so you can't reference it in B if you keep using netstandard.
LibVLCSharp can be moved "up" in project B if you need it there.
Long answer:
Let's see the packages in detail:
VideoLAN.LibVLC.Windows : This package contains the required dlls files that are required to make libvlc work on Windows. It also contains msbuild files that are used to copy the DLLs to the output directory of your project. You need those files in your application, so you need to reference this package in A. (They won't be transitively copied by a Project reference)
LibVLCSharp.WinForms : As stated here, this package only support .NET framework 4.0 and above, and .net core 3.0 and above. You will not be able to add this package in B, unless you replace your netstandard constraint and use multi-targetting instead. It will only work where WinForms is available.
LibVLCSharp can be referenced in project B without any issue. Since you're using .net standard, chances are you are also using the "SDK-style" csproj format and PackageReference. The dependency will then transitively be available in project A without adding it there.
If your point was having a player Form available in both .net framework and .net core, I'd recommend that you use multi targetting, by putting this in your B project:
<TargetFrameworks>net40;netcoreapp3.0</TargetFrameworks>
otherwise, if it's just for sharing non-ui code, you don't need the LibVLCSharp.WinForms dependency in B

Why is my .NET framework app looking for the wrong version of the .NET core/standard platform extension assembly, and how do I fix it?

From the .NET APIs catalog, I understand that the Microsoft.Win32.Registry class is declared in the .NET Standard + Platform Extensions 2.0 package in an assembly Microsoft.Win32.Registry, Version=4.1.1.0, PublicKeyToken=b03f5f7f11d50a3a.
I've created a class library which targets .NET Standard 2.0, and here's a simple class:
public class NetStandardClass
{
public string GetHklmRegValue()
{
var lmKey = Microsoft.Win32.Registry.LocalMachine;
var softwareKey = lmKey.OpenSubKey("Software");
return "value";
}
}
I've created a .NET Framework 4.7.2 console application which references my above class library:
class Program
{
static void Main(string[] args)
{
string value = new ClassLibrary2.NetStandardClass().GetHklmRegValue();
}
}
When I run this on Windows, this throws a run-time exception:
System.IO.FileNotFoundException: 'Could not load file or assembly
'Microsoft.Win32.Registry, Version=4.1.3.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The
system cannot find the file specified.'
Based on what I've read, having assembly load issues in this scenario is somewhat of a known issue. The prescribed work-around is to enable automatic binding redirects and make sure my .NET Framework application is using PackageReference rather than Project.Config. I have done this with my projects from which I shared the above code, but I'm still getting the error. What confuses me most, though, is that the error is indicating the .NET Core / .NET Core + Platform Extensions assembly (Version=4.1.3.0, PublicKeyToken=b03f5f7f11d50a3a) rather than the .NET Standard (Version=4.1.1.0, PublicKeyToken=b03f5f7f11d50a3a) or .NET Framework (Version=4.0.0.0, PublicKeyToken=b77a5c561934e089) versions from the APIs catalog:
This is further corroborated by the Microsoft.Win32.Registry.DLL that is in the output directory:
Based on further reading, I can make a little progress by doing either of the following:
Add <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> to the .NET Standard class library proj file
-- or --
Add the Microsoft.Win32.Registry NuGet package directly to my .NET Framework console application.
Either of these results in loading some version of the assembly, but then I get some odd behavior: I get an NRE for the LocalMachine property, which shouldn't happen.
So here are the questions:
1.) Since my project is a .NET Framework application, why is it not using the Microsoft.Win32.Registry class in the .NET Framework API, specifically the mscorlib assembly that the same APIs catalog refers to?
2.) Why isn't the "work around" in the GitHub post not working for me?
3.) Why is it seemingly looking for the .NET Core / ... extensions version of the assembly?
4.) Why when I explicitly export the NuGet Microsoft.Win32.Registry assembly in the .NET Standard class library or directly reference the package in the .NET Framework console application does it result in the strange behavior where Microsoft.Win32.Registry.LocalMachine is null, which should never be the case on a Windows machine?
The following answers make an assumption of having the newest version of Visual Studio 2019 (v16.4.3 at time of writing) installed, as this may have some effect on the outcome.
Question 1):
1.) Since my project is a .NET Framework application, why is it not using the Microsoft.Win32.Registry class in the .NET Framework API, specifically the mscorlib assembly that the same APIs catalog refers to?
This will actually use the v4.0.0.0 mscorlib Registry class when the projects are set up in either of the following manners:
Option 1
Class library: Target Framework = netstandard2.0, NuGet packages = Microsoft.Windows.Registry (v4.5.0)
Console app: Target Framework = net472, NuGet is set to "packages.config" mode, NuGet packages = Microsoft.Windows.Registry (v4.5.0) [and also AccessControls and Principal.Windows, as they are dependencies]
NOTE: Here, if you don't add the Microsoft.Windows.Registry package, you typically will get the runtime error looking for version 4.1.1.0 of the Registry dll. But I believe the version it looks for is based on what the current .NET Core SDK version you have installed.
Option 2 [I think this is the one you really want]
Class library: Target Framework = netstandard2.0, NuGet packages = Microsoft.Windows.Registry (v4.5.0)
Console app: Target Framework = net472, NuGet is set to "PackageReference" mode, NuGet packages = None
NOTE: In VS2019, if you have the option for "Allow format selection on first package install" checked, then it will allow you to choose to use the PackageReference style, where NuGet packages are referenced in the project file instead of packages.config. Typically you have to install any one NuGet package just to set this mode, but afterward can uninstall that package and it will stay in that mode. I believe you could also set the default mode as well, before you first create your net472 project.
NOTE: Here, the PackageReference mode seems to help resolve the NuGet dependencies on the other .NET Standard 2.0 class library, where as the package.config mode requires you to do it yourself it seems.
This should be easily reproducible, however, things that can cause some sort issue can be any of:
- older versions of VS2019 being used
- skipping binding redirects setting turned on for NuGet in VS
- auto binding redirects turned off for the .NET 4.7.2 project
- not "rebuilding" the solution after package or reference changes
- not restarting the computer after installing/updating .NET SDK's or VS2019 updates
- still having a packages.config file
I'd also like to note that in Option 1 above, I found in testing this out that if you don't add the Microsoft.Windows.Registry package, it fails on runtime looking for version 4.1.1.0 of the registry dll. But, I was able to get it to fail looking for runtime 4.1.3.0 by first installing Microsoft.Windows.Registry 4.7.0, and then I uninstalled it (thereby leaving the two dependent packages AccessControl and Principal.Windows), and without rebuilding the project: if I run it, it fails on runtime with the 4.1.3.0 version being the one it's looking for. Rebuilding it reverts back to 4.1.1.0. This remains the same even if I remove the two dependent packages. Note: this also works if you simply remove the references to the dll's in the project, rather than uninstalling the NuGet packages.
Question 2):
2.) Why isn't the "work around" in the GitHub post not working for me?
I have a feeling this is happening because you may have an older version of VS2019 than 16.4.3. I found that when I was using an older version, the PackageReference mode still resulted in the runtime error. When I updated (sorry, I am not sure which exact revision actually fixes it) VS2019 to 16.4.3, this seems to now just work. I am not sure if this is some sort of unexpected interaction with the various SDK's (perhaps some being more recently released but not supported by an older revision of VS). It could also be an issue if the packages.config file is still lingering around.
Another issue could potentially be interference by other NuGet packages that may be installed and have different library version requirements.
Question 3):
3.) Why is it seemingly looking for the .NET Core / ... extensions version of the assembly?
In a .NET 4.7.2 project that references a .NET Standard 2.0 (.NET standard projects are .NET Core projects by default), it will utilize the .NET Core framework, not the .NET framework. So any references to the Registry are not by default available. You need the Microsoft.Windows.Registry packages (at the least) to allow use of the Registry, which I believe has the ability to act as a shim to the .NET 4.7.2 mscorlib verison of the library if available, but use the 4.1.1.0 version as a fallback (or 4.1.3.0 version if you're referencing from a .NET Core project instead).
Question 4):
4.) Why when I explicitly export the NuGet Microsoft.Win32.Registry assembly in the .NET Standard class library or directly reference the
package in the .NET Framework console application does it result in
the strange behavior where Microsoft.Win32.Registry.LocalMachine is
null, which should never be the case on a Windows machine?
I haven't personally tested this, and didn't run into this issue when I tested the above, but my feeling on this is that the dll's are likely missing their dependent dll's. But thinking about that further, would likely just result in another runtime error if that's the case. I think the issue is that they aren't intended to be directly exported and something may be missing along the way.
I'd also note that if you run this on any platform other than Windows, the registry is likely to come back as null since I think it wouldn't exist on, say, a Linux runtime.
Other Notes:
I get a general sense that this sort of thing has been a little buggy with VS and .NET Core in general referencing to/from .NET Framework, and that there's progress being made regularly to improve this.
I found also that there are some surprising issues I ran into that I didn't expect. For example, creating a .NET Standard console app, referencing the .NET Standard class library, and still getting the runtime error, no matter what packages I installed on the console app. You would think the exact same target framework would just work without any special configurations, but it doesn't seem to. But if you create a .NET Core console app instead, it does work properly. It's a bit mystifying, but there's always a technical explanation somewhere in the mix.

Using two different versions of same the NuGet package

I wanted to use two different version same library (OpenCVSharp 2.x and OpenCVSharp 3.x).
I downloaded those two packages both to the separate project (let's call it OCV2Wrapper and OCV3Wrapper) and reference both wrappers in my project. I had to renamed libraries from one package (2.x) and reference them manual because: Can we add 2 different versions of same package in NuGet. I read about external aliases and I used external alias in one of the wrappers (2.x in my case).
But I have some major problems:
My renamed libraries are not copied to the launch project build (that one which reference both wrappers), but is in build of the 2.x wrapper
It doesn't work because yet it says it cannot find a type from my 2.x wrapper even when I manually copy my renamed libraries from 2.x wrapper.
What is the correct approach for this scenario in C#?
I want to use both wrappers in solution because the 2.x version contains algorithms (SIFT and SURF) and 3.x version contains algorithms (Kaze and AKaze).
I can live that with both packages coming from somewhere other than NuGet, but I prefer that 3.x comes from NuGet and the 2.x version is manually configured.
As already stated, there is nothing wrong with referencing 2 different versions of a NuGet package, as long as it's in different Visual Studio Projects that those references are made.
But this is also where the easy part ends, but I think there are a few options left. Depending on your needs, I see the following options.
Create a post build step which registers the multi-versioned assemblies into the GAC. As long as each assembly have different assembly version, the CLR will pick up the right assembly from the GAC when needed.
Create a post build step which copies the different assemblies into a subfolder of your application bin folder like bin/package-v1 and bin/package-v2. Then you can, in your application, override the AssemblyResolve event as described here: https://msdn.microsoft.com/en-us/library/ff527268(v=vs.110).aspx. This will make it possible for you to load the assembly in the right version at the time of need.
If you don't want to play around with AssemblyResolve, then you can also modify your web/app.config to do assembly redirect/probing as described here: https://msdn.microsoft.com/en-us/library/4191fzwb(v=vs.110).aspx
Hope this helps a bit, so you don't have to modify third party source code next time.
OK so, I solve this by downloading whole sourcecode for 2.X wrapper version.
Renamed its namespace to ABCDEF2 where ABCDEF was original namespace. Build my own nuget package with my own key and... publish it to our private nuget server.
This is such a lame solution but there is no other way than manually downloading the original packages and reference it directly with different filename etc and you loose nuget advantages.

Xamarin.Mac 4.5 with BCL Async release compile fails to resolve System.Threading.Tasks

I have been using .NET 4.5 in Xamarin Studio with portable libraries and a Xamarin.Mac project. When the Xamarin.Mac project is set to .NET 4.5 and Microsoft Async is added via nuget, compile in Debug will succeed but Release/AppStore will fail with
error MM2002: Failed to resolve assembly: 'System.Threading.Tasks,
In this case, it is unnecessary to add the dlls (System.Threading.Tasks and System.Runtime) from BCL because they are already in .NET 4.5. If you switch to .NET 4.0 it will work, but I have a lot of code already in .NET 4.5 that cannot be reversed because of other dependencies.
Somehow, BCL is not recognizing the Xamarin.Mac .NET 4.5 project as .NET 4.5 and still requiring the dlls.
To replicate:
Create a new Xamarin.Mac project
Set it to .NET 4.5
Use nuget to fetch Microsoft Async (notice correctly it does not pull in System.Threading.Tasks or System.Runtime)
Switch to Release
Compile
How does BCL know if .NET 4.0 or .NET 4.5 is used? Maybe there is something I can declare in the csproj to make it recognize that System.Threading.Tasks (and System.Runtime) is already included. Or maybe some Environment variable? Or...?
Note. It is possible to reference the System.Threading.Tasks ans System.Runtime from the net40 nuget folder. And in the test project, this actually works - though it complains about "The predefined type System.Runtime.CompilerServices.AsyncStateMachineAttribute' is defined multiple times. Using definition frommscorlib.dll'" However, in my case I have a portable library which uses EventArgs and the build fails with error CS1684: Reference to type System.EventArgs' claims it is defined assemblySystem.Runtime - which of course it isn't.
I'm not sure how well Xamarin.Mac supports PCLs. You can try to add an app.config with binding redirects, similar to what is described here: http://motzcod.es/post/78863496592/portable-class-libraries-httpclient-so-happy
Otherwise, I'd suggest filing a bug with Xamarin.

async/await in .NET 4.0: a Compatibe Set of DLLs?

I would like to use async/await syntax when targeting .NET FX 4.0.
I fetched the Microsoft.Bcl.Async.1.0.168 Nuget package. It has the assembly Microsoft.Threading.Tasks, Version=1.0.12.0 which implements all the magic and has a reference to System.Runtime, Version=1.5.11.0.
The System.Runtime assembly is available in the companion Nuget package Microsoft.Bcl.1.1.8, but has a different version 2.6.8.0 in there.
As a result, its usages won't compile without special tricks and hacks.
The DLL reference does not resolve because of the version number mismatch.
So, is it possible to get a consistent set of BCL Async DLLs which reference one another by matching version numbers and which can be compiled right away?
(Tried looking in other Nuget versions or other target ilb folders, found some matching versions but they're for a different platform and with a different set of classes, e.g. with a duplicate Task class)
UPD: Also mind the runtime behavior: with netfx45, these assemblies get unified into runtime and work like a charm, but on a vanilla netfx40 system you'd get a System.IO.FileLoadException with Could not load file or assembly 'System.Threading.Tasks, Version=1.5.11.0, […]
All you need is the one Nuget package, and VS2012 or higher. (with Nuget 2.3 or higher)
https://www.nuget.org/packages/Microsoft.Bcl.Async
Nuget will install all dependencies with the correct version (unless you specify otherwise). I've done this many times, and I'll tell you right now you only need to use that one package, and if its not working there is something else wrong with your setup.
If you don't have VS2012, you can download the Express (free) version in order to use this.
If my word isnt enough, you can read the official MSDN blog on the subject.
http://blogs.msdn.com/b/bclteam/archive/2012/10/22/using-async-await-without-net-framework-4-5.aspx
http://blogs.msdn.com/b/bclteam/archive/2013/04/17/microsoft-bcl-async-is-now-stable.aspx

Categories

Resources