繁体   English   中英

为什么我的 .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?

.NET APIs 目录中,我了解到Microsoft.Win32.Registry类是在.NET Standard + Platform Extensions 2.0程序包中声明的Microsoft.Win32.Registry, Version=4.1.1.0, PublicKeyToken=b03f5f7f11d50a3a

在此处输入图片说明

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

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 Program
{
    static void Main(string[] args)
    {
        string value = new ClassLibrary2.NetStandardClass().GetHklmRegValue();
    }
}

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

System.IO.FileNotFoundException: '无法加载文件或程序集 'Microsoft.Win32.Registry, Version= 4.1.3.0 , Culture=neutral, PublicKeyToken= b03f5f7f11d50a3a ' 或其依赖项之一。 该系统找不到指定的文件。'

根据我所读到的内容,在这种情况下出现程序集加载问题在某种程度上是一个已知问题。 规定的解决方法是启用自动绑定重定向并确保我的 .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(版本=4.0.0.0,PublicKeyToken=b77a5c561934e089 )来自 API 目录的版本:

在此处输入图片说明

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

在此处输入图片说明

根据进一步阅读,我可以通过执行以下任一操作来取得一些进展:

  • <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>到 .NET Standard 类库项目文件

- 或者 -

  • Microsoft.Win32.Registry NuGet 包直接添加到我的 .NET Framework 控制台应用程序。

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

在此处输入图片说明


所以这里是问题:

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

在此处输入图片说明

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 包在项目文件中引用而不是 packages.config。 通常,您必须安装任何一个 NuGet 包才能设置此模式,但之后可以卸载该包并保持该模式。 我相信您也可以在首次创建 net472 项目之前设置默认模式。
      • 注意:在这里,PackageReference 模式似乎有助于解决对其他 .NET Standard 2.0 类库的 NuGet 依赖关系,而 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 版本的垫片(如果可用),但使用4.1.1.0 版本作为后备(或 4.1.3.0 版本,如果您从 .NET Core 项目引用)。

问题 4):

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

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

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

其他注意事项:

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM