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
Related
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.
I have a library written in full .NET and I am porting it to .NET Core. I intend to make it target the .netstandard1.1 (in order to be also compatible with .NET45).
When I create the project with visual studio, it automatically depends on the NETStandard.Library nuget package.
My library only needs two packages:
System.Runtime
System.Runtime.InteropServices
Two questions :
Do I need to restrict my project dependencies to only these two packages? Rephrased: may be nuget (or visual studio or another magic stuff) manage to restrict on its own to only the needed packages and not the full NETStandard.Library?
If the answer to the first question is no, is it a good idea to perform that restriction?
Thanks in advance.
(Sorry for my english, I am not a native speaker)
There are some aspects in your question...
The netstandard1.1 framework choice will limit your available API surface in the editor (here VS Code) to what is available that version. Just tested with File.OpenRead on VS Code for netstandard1.1 (not available) and netstandard1.6 (available).
The NETStandard.Library dependency (version 1.6 is good for both cases) is a package dependency. Once the assembly is compiled, the assembly itself will declare external assemblies (aka referenced assemblies) which were actually used (e.g. System.Runtime and System.Linq) and not all assemblies found in the NETStandard.Library meta package.
As long as you are not packaging it up for NuGet, assembly reference restrictions are anyway done for you. NuGet packaging however would refer to the NETStandard.Library package
If you use NuGet and that reduction is important to you, I guess the correct term is NuGet dependency trimming, a manual process explained here (short version: copy all references from the meta package and remove all you do not use).
I am not sure if it's a VS bug, however seems like VS doesn't like building a library and not having a NETStandard.Library package included :) So, no.
Unless you use Visual Studio Code or Notepad etc. this will slow down your development, since VS will prevent you from building the project etc. So, no again.
The bottom line.
Premature optimization might cause more issues than benefit. Port your library first, and only then check if you need to optimize it.
According to MSDN:
When you build a .NET Framework application against a specific version
of a strong-named assembly, the application uses that version of the
assembly at run time.
https://msdn.microsoft.com/en-us/library/7wd6ex19(v=VS.100).aspx
Question
Is there a way, to build a .Net Framework application against a strong-named assembly, so that it does not require the specific version at run time?
The quote from MSDN seems to imply that ("against a specific version of a strong-named assembly")
But how to do that. How do I build against a non specific version of a strong named assembly?
All tests I did tell me, that if I build against a strong named assembly, it will always require that version at runtime.
Except when I use Publisher Policys or Assembly Redirects.
Update:
But when I check for example this nuget Package:
https://www.nuget.org/packages/Microsoft.Owin.Security.OAuth.
It says that it accepts Newtonsoft.Json greater then 6.0.4.
And I want to understand how they do that? Since Newtonsoft.Json is a strongly named assembly. And I don't see any assembly redirects and I think there is also no publisher policy. Or do I miss something?
This is handled by assembly redirection, as you've already mentioned.
The NuGet dependency management for the packet manager itself, not the assembly references. You still have strict binding for the references in your project, and this can cause collisions when you end up with two versions of the same assembly in the same AppDomain as usual. NuGet doesn't even try to solve the problem.
When that conflict arises, you're back to square one - you need to add binding redirects. If that isn't possible (for incompatible versions of the assembly, for example), you're in for a lot of fun.
The policy NuGet uses to pick the best version of the library is quite simple: get the lowest possible major + minor version, and the highest possible patch version (the third version number). Again, this only happens when updating the packages, not at compile-time or runtime. This allows NuGet to pick a compatible version of a dependency when you have multiple packages that have different requirements. However, it isn't transitive - it only helps if all your references are in the same project. If you're referencing a project that NuGet's a different version of the dependency, you're back at the original problem again.
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.
I'v not been too long on the .net platform.less than 2months.
I'm having this "could not load type blah.blah.blah from assembly blah.
So i'v been battling it with several resources including the suggestions in diff post here.Still no luck. but the closest suggestion seems to indicate that some of references might be targeting a lower version of .net.
Actually there are many many references targeting different versions and within some of this references there are many more dependent assemblies that possibly are targeting diff versions.
i'v been struggling to convert some of the assemblies i have the source using VS 2010(.net 4.0) and the whole stuff is almost overwhelming me.
And so i'm asking in frustration: MUST MY REFERENCE ASSEMBLIES(and their dependencies) AND MY PROJECT TARGET the same version?
As long as the libraries target a version that is <= the version your code wants, then that is fine. Note, of course, that any behavior changes could cause subtle bugs, but this is rare - fundamentally it should work ok.
If the libraries target a higher version: bad things.
I suspect more context about the specific "could not load type blah.blah.blah from assembly blah." would be useful.
No it is not necessary REFERENCE ASSEMBLIES(and their dependencies) AND Your PROJECT TARGET the same version.
I think you got another issue for could not load project or assembly.
Keep in mind
1> Add all assembly which is missing
2> don't run 4.0 targeting project in 2008 or lower (don't run higher version project in lower version SDK)