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:
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
to the .NET Standard class library proj file-- or --
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?
Application Models. Net Core does not support desktop application development and it rather focuses on the web, windows mobile, and windows store. . Net Framework is used for the development of both desktop and web applications as well as it supports windows forms and WPF applications.
NET Framework 4.5 and later versions are backward-compatible with apps that were built with earlier versions of the . NET Framework. In other words, apps and components built with previous versions will work without modification on the . NET Framework 4.5 and later versions.
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.
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
Option 2 [I think this is the one you really want]
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.
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.
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).
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.
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.
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