为什么我的 .NET Framework 应用程序寻找错误版本的 .NET core/standard 平台扩展程序集,我该如何解决?

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?

the .NET APIs catalog,我了解到Microsoft.Win32.Registry class 是在程序集Microsoft.Win32.Registry, Version=4.1.1.0, PublicKeyToken=b03f5f7f11d50a3a.NET Standard + Platform Extensions 2.0 包中声明的。

我创建了一个针对 .NET Standard 2.0 的 class 库,下面是一个简单的 class:

public class NetStandardClass
{
    public string GetHklmRegValue()
    {
        var lmKey = Microsoft.Win32.Registry.LocalMachine;
        var softwareKey = lmKey.OpenSubKey("Software"); 
        return "value";
    }
}

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

class Program
{
    static void Main(string[] args)
    {
        string value = new ClassLibrary2.NetStandardClass().GetHklmRegValue();
    }
}

当我在 Windows 上 运行 时,这会引发 运行 时间异常:

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.'

基于 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 并确保我的 .NET Framework 应用程序使用 PackageReference 而不是 Project.Config。我已经在共享上述代码的项目中完成了此操作,但我仍然遇到错误。不过,最让我困惑的是错误指示 .NET Core / .NET Core + Platform Extensions 程序集(Version=4.1.3.0,PublicKeyToken=b03f5f7f11d50a3a)而不是.NET Standard(Version=4.1.1.0,PublicKeyToken=b03f5f7f11d50a3a)或 .NET Framework(Version=4.0.0.0,PublicKeyToken=b77a5c561934e089)版本来自 APIs 目录:

微软进一步证实了这一点。Win32.Registry.DLL在输出目录中:

的基础上,我可以通过以下任一方式取得一点进步:

-- 或--

这些中的任何一个都会导致加载 某些版本 的程序集,但随后我会出现一些奇怪的行为:我得到了 LocalMachine 属性,这不应该发生。


下面是问题:

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

2.) 为什么 GitHub post 中的 "work around" 对我不起作用?

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

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

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

问题 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?

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

  • 选项 1

    • Class 库:目标框架 = 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 程序包,您通常会在查找 Registry dll 版本 4.1.1.0 时遇到 运行 时间错误。但我相信它寻找的版本是基于您当前安装的 .NET Core SDK 版本。
  • 选项2[我想这才是你真正想要的]

    • Class 库:目标框架 = netstandard2.0,NuGet 包 = Microsoft.Windows.Registry (v4.5.0)
    • 控制台应用程序:目标框架 = net472,NuGet 设置为 "PackageReference" 模式,NuGet 包 = None
      • 注意:在 VS2019 中,如果您勾选了 "Allow format selection on first package install" 选项,那么它将允许您选择使用 PackageReference 样式,其中在项目文件中引用 NuGet 包而不是 packages.config.通常,您必须安装 any 一个 NuGet 包才能设置此模式,但之后可以卸载该包,它将保持该模式。我相信您也可以在首次创建 net472 项目之前设置默认模式。
      • 注意:此处,PackageReference 模式似乎有助于解决 NuGet 对其他 .NET Standard 2.0 class 库的依赖性,而 package.config 模式似乎需要您自己完成.

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

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

问题 2):

2.) Why isn't the "work around" in the GitHub post not working for me?

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

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

问题 3):

3.) Why is it seemingly looking for the .NET Core / ... extensions version of the assembly?

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

问题 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?

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

我还要注意,如果您 运行 在除 Windows 以外的任何平台上执行此操作,注册表很可能会返回为 null,因为我认为它不会存在,比如,一个Linux运行时间.

其他注意事项:

我总的感觉是,在一般参考 to/from .NET Framework 时,这种事情在 VS 和 .NET Core 中存在一些小问题,并且在定期改进这一点方面取得了进展。

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