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

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

问题描述



我创建了一个针对.NET Standard 2.0,这是一个简单的类:

 公共类NetStandardClass 
{
public string GetHklmRegValue ()
{
var lmKey = Microsoft.Win32.Registry.LocalMachine;
var softwareKey = lmKey.OpenSubKey( Software);
返回值;
}
}

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

  class程序
{
static void Main(string [ ] args)
{
字符串值= new ClassLibrary2.NetStandardClass()。GetHklmRegValue();
}
}

在Windows上运行此命令时-time例外:


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。)为什么当我在其中显式导出NuGet Microsoft.Win32.Registry 程序集时.NET Standard类库或直接引用.NET Framework控制台应用程序中的包,会导致奇怪的行为,其中 Microsoft.Win32.Registry.LocalMachine 为null,这

解决方案

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



问题1):




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


这实际上将使用vcor.v4.0.0.0通过以下两种方式之一设置项目时,注册表类:




  • 选项1




    • 类库:目标框架= netstandard2.0,NuGet软件包= Microsoft.Windows .Registry(v4.5.0)

    • 控制台应用程序:目标框架= net472,NuGet设置为 packages.config模式,NuGet软件包= Microsoft.Windows.Registry(v4.5.0) [以及AccessControls和Principal.Windows,因为它们是相关的ies]


      • 注意:在这里,如果不添加Microsoft.Windows.Registry包,则通常会在运行4.1版时出现运行时错误。注册表dll的1.0。但是我相信它查找的版本基于您所安装的当前.NET Core SDK版本。


  • >
  • 选项2 [我认为这是您真正想要的那个]




    • 类库:目标框架= netstandard2.0,NuGet软件包= Microsoft.Windows.Registry(v4.5.0)

    • 控制台应用程序:目标框架= net472,NuGet设置为 PackageReference模式,NuGet软件包=无


      • 注意:在VS2019中,如果选中了允许在首次安装软件包时选择格式,则它将将允许您选择使用PackageReference样式,在该样式中,在项目文件中引用了NuGet包而不是packages.config。通常,您只需要安装 any 个NuGet软件包即可设置此模式,但是此后可以卸载该软件包,它将保持该模式。我相信您也可以在首次创建net472项目之前也设置默认模式。

      • 注意:在这里,PackageReference模式似乎有助于解决对另一个.NET的NuGet依赖项。标准的2.0类库,在package.config模式下,您似乎需要自己做。





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



我也想请注意,在上面的选项1 中,我在测试时发现,如果您不添加e.Microsoft.Windows.Registry程序包,在运行时查找注册表dll的4.1.1.0版失败。但是,通过首先安装Microsoft.Windows.Registry 4.7.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 4.7.2项目中.NET Standard 2.0(默认情况下,.NET标准项目是.NET Core项目),它将使用.NET Core框架,而不是.NET框架。因此,默认情况下不提供对注册表的任何引用。您需要Microsoft.Windows.Registry程序包(至少)以允许使用注册表,我认为它可以充当库的.NET 4.7.2 mscorlib版本的填充程序,但请使用作为备用的4.1.1.0版本(如果您是从.NET Core项目引用的,则为4.1.3.0版本)。



问题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 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 Framework应用程序查找错误版本的.NET Core /标准平台扩展程序集,如何解决?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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