为什么我的 .NET 框架应用程序会寻找错误版本的 .NET 核心/标准平台扩展程序集,我该如何解决? [英] 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?

查看:17
本文介绍了为什么我的 .NET 框架应用程序会寻找错误版本的 .NET 核心/标准平台扩展程序集,我该如何解决?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个面向 .NET Standard 2.0 的类库,这是一个简单的类:

公共类 NetStandardClass{公共字符串 GetHklmRegValue(){var lmKey = Microsoft.Win32.Registry.LocalMachine;var softwareKey = lmKey.OpenSubKey("软件");返回值";}}

我创建了一个 .NET Framework 4.7.2 控制台应用程序,它引用了我上面的类库:

class 程序{静态无效主(字符串 [] args){字符串值 = new ClassLibrary2.NetStandardClass().GetHklmRegValue();}}

当我在 Windows 上运行它时,会抛出一个运行时异常:

<块引用>

System.IO.FileNotFoundException: '无法加载文件或程序集'Microsoft.Win32.Registry,版本=4.1.3.0,文化=中性,PublicKeyToken=b03f5f7f11d50a3a' 或其依赖项之一.这系统找不到指定的文件.'

根据

输出目录中的 Microsoft.Win32.Registry.DLL 进一步证实了这一点:

基于

<小时>

所以这里是问题:

1.) 由于我的项目是 .NET Framework 应用程序,为什么不使用 .NET Framework API 中的 Microsoft.Win32.Registry 类,特别是 mscorlib相同API目录引用的程序集?

2.) 为什么 GitHub 帖子中的解决方法"对我不起作用?

3.) 为什么它似乎在寻找程序集的 .NET Core/... 扩展版本?

4.) 为什么当我显式导出 .NET Standard 类库中的 NuGet Microsoft.Win32.Registry 程序集或直接引用 .NET Framework 控制台应用程序中的包时,会导致Microsoft.Win32.Registry.LocalMachine 为空的奇怪行为,在 Windows 机器上绝不应该出现这种情况?

解决方案

以下答案假设安装了最新版本的 Visual Studio 2019(撰写本文时为 v16.4.3),因为这可能会对结果.

问题 1):

<块引用>

1.) 由于我的项目是 .NET Framework 应用程序,为什么不使用 .NET Framework API 中的 Microsoft.Win32.Registry 类,特别是同一 API 目录所引用的 mscorlib 程序集?

当以下列任一方式设置项目时,这实际上将使用 v4.0.0.0 mscorlib Registry 类:

  • 选项 1

    • 类库:目标框架 = netstandard2.0,NuGet 包 = Microsoft.Windows.Registry (v4.5.0)
    • 控制台应用程序:目标框架 = net472,NuGet 设置为packages.config"模式,NuGet 包 = Microsoft.Windows.Registry (v4.5.0) [还有 AccessControls 和 Principal.Windows,因为它们是依赖项]
      • 注意:在这里,如果您不添加 Microsoft.Windows.Registry 包,您通常会在查找 4.1.1.0 版 Registry dll 时遇到运行时错误.但我相信它查找的版本基于您安装的当前 .NET Core SDK 版本.
  • 选项 2 [我认为这是您真正想要的]

    • 类库:目标框架 = netstandard2.0,NuGet 包 = Microsoft.Windows.Registry (v4.5.0)
    • 控制台应用:目标框架 = net472,NuGet 设置为PackageReference"模式,NuGet 包 = 无
      • 注意:在 VS2019 中,如果您选中了首次安装包时允许格式选择"选项,那么它将允许您选择使用 PackageReference 样式,其中 NuGet 包在项目文件中被引用而不是包.config.通常,您必须安装任何一个 NuGet 包才能设置此模式,但之后可以卸载该包并保持该模式.我相信您也可以在首次创建 net472 项目之前设置默认模式.
      • 注意:这里,PackageReference 模式似乎有助于解决 NuGet 对其他 .NET Standard 2.0 类库的依赖关系,而 package.config 模式似乎要求您自己完成.

这应该很容易重现,但是,可能导致某种问题的事情可能是:- 正在使用旧版本的 VS2019- 在 VS 中为 NuGet 开启跳过绑定重定向设置- .NET 4.7.2 项目的自动绑定重定向关闭- 在包或参考更改后不重建"解决方案- 安装/更新 .NET SDK 或 VS2019 更新后不重新启动计算机- 仍然有一个packages.config 文件

我还想指出,在上面的选项 1 中,我在测试中发现如果您不添加 Microsoft.Windows.Registry 包,它将在运行时查找失败注册表 dll 的 4.1.1.0 版.但是,通过首先安装 Microsoft.Windows.Registry 4.7.0,我能够让它在查找运行时 4.1.3.0 时失败,然后我卸载了它(从而留下了两个依赖包 AccessControl 和 Principal.Windows),并且 无需 重建项目:如果我运行它,它会在运行时失败,而 4.1.3.0 版本正是它正在寻找的版本.重建它会恢复到 4.1.1.0.即使我删除了两个依赖包,这也保持不变.注意:如果您只是删除对项目中 dll 的引用,而不是卸载 NuGet 包,这也适用.

问题 2):

<块引用>

2.) 为什么 GitHub 帖子中的解决方法"对我不起作用?

我有一种感觉,因为您的 VS2019 版本可能比 16.4.3 旧.我发现在使用老版本的时候,PackageReference模式还是会导致运行时错误.当我将 VS2019 更新到 16.4.3 时(抱歉,我不确定哪个确切的修订版实际上修复了它),这似乎现在可以正常工作了.我不确定这是否是与各种 SDK 的某种意外交互(也许有些是最近发布的,但不受较旧版本的 VS 支持).如果packages.config 文件仍然存在,也可能是一个问题.

另一个问题可能是受到其他可能已安装且具有不同库版本要求的 NuGet 包的干扰.

问题 3):

<块引用>

3.) 为什么它似乎在寻找程序集的 .NET Core/... 扩展版本?

在引用 .NET Standard 2.0(.NET 标准项目默认为 .NET Core 项目)的 .NET 4.7.2 项目中,它将使用 .NET Core 框架,而不是 .NET 框架.因此,默认情况下不提供对注册表的任何引用.您需要 Microsoft.Windows.Registry 包(至少)以允许使用注册表,我相信它可以作为库的 .NET 4.7.2 mscorlib verison(如果可用)的垫片,但使用4.1.1.0 版本作为后备(或 4.1.3.0 版本,如果您从 .NET Core 项目引用).

问题 4):

<块引用>

4.) 为什么当我在 .NET Standard 类库中显式导出 NuGet Microsoft.Win32.Registry 程序集或直接引用.NET Framework 控制台应用程序中的包是否会导致Microsoft.Win32.Registry.LocalMachine 的奇怪行为null,在 Windows 机器上绝不应该是这种情况?

我没有亲自测试过这个,当我测试上述内容时也没有遇到这个问题,但我的感觉是 dll 可能缺少它们依赖的 dll.但进一步考虑,如果是这种情况,可能只会导致另一个运行时错误.我认为问题在于它们不打算直接导出,并且在此过程中可能会丢失一些东西.

我还要注意,如果您在 Windows 以外的任何平台上运行它,注册表可能会返回 null,因为我认为它不会存在于,例如,Linux 运行时.

其他注意事项:

我有一个普遍的感觉,VS 和 .NET Core 通常引用/来自 .NET Framework,这种事情有点问题,并且正在定期取得进展以改进这一点.

我还发现我遇到了一些出乎意料的令人惊讶的问题.例如,创建 .NET Standard 控制台应用程序,引用 .NET Standard 类库,但仍然出现运行时错误,无论我在控制台应用程序上安装什么包.您会认为完全相同的目标框架无需任何特殊配置即可工作,但似乎并非如此.但是,如果您改为创建 .NET Core 控制台应用程序,它确实可以正常工作.这有点令人费解,但总有一些技术性的解释在其中.

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.

这篇关于为什么我的 .NET 框架应用程序会寻找错误版本的 .NET 核心/标准平台扩展程序集,我该如何解决?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆