混合了 .netstandard2.0 和 .netframework47 的 DLLs 在 nuget 包中 – .netstandard 不可用

huangapple go评论120阅读模式
英文:

Mix of .netstandard2.0 and .netframework47 DLLs in nuget package - .netstandard not available

问题

首先,我不确定我正在做的是否基本上是错误的想法,所以答案可能只是不要这样做,但还是要尝试一下。

我正在创建一个包,它的信息来自一个 .nuspec 文件,在它的 "files" 部分包含对 .net standard 和 .net framework DLLs 的引用。它还依赖于 .netstandard20 和 .netframework47。

这是因为旧版库是使用 framework 编写的,而新版库是使用 standard 编写的。

我们有一个消耗该包的项目(实际上有好几个),它是在 .netframework 4.7 中编写的,需要同时引用这两组 DLLs。我已经更改了项目,使用 PackageReference 而不是 packages.config,并且 Visual Studio 显示包正在被引用(而不是单独的命名空间)在 References 部分。但是,在构建项目时,.netframework 的 DLLs 会被复制到 bin 文件夹中,但 .netstandard 的 DLL 不会。

我创建了一个临时项目来隔离问题,结果我在那里也遇到了同样的问题。该项目基本上就是拒绝承认 standard 的那部分。如果我在一个类中添加一个使用 .netstandard DLL 中的类型的 using 语句,它会在下面画出红色的波浪线,并告诉我它不存在于命名空间中。

有人建议我将 .netstandard DLLs 拆分成它们自己的 NuGet 包,这是否是答案,还是我漏掉了什么?

以下是一些示例...

.nuspec 文件:

<?xml version="1.0" encoding="utf-8"?>
<package >
  <metadata minClientVersion="2.5">
    <!-- 其他标签已省略以缩短篇幅 -->
    <dependencies>
      <group targetFramework=".NETStandard2.0"></group>
      <group targetFramework=".NETFramework4.7">
        <dependency id="NLog" version="3.1.0.0" />
      </group>
    </dependencies>
  </metadata>
  <files>
    <file src="..\Src\MyProj1\bin\Release\netstandard2.0\NetStandardClass.dll" target="lib\netstandard2.0" />
    <file src="..\Src\MyProj2\bin\Release\NetFrameworkClass1.dll" target="lib\net47" />
    <file src="..\Src\MyProj3\bin\Release\NetFrameworkClass2.dll" target="lib\net47" />
  </files>
</package>

该包被引用为一个包,而不是其中的单个类型:

混合了 .netstandard2.0 和 .netframework47 的 DLLs 在 nuget 包中 – .netstandard 不可用

如果我尝试手动添加一个引用 NetStandardClass 命名空间的 using 语句,它会标记为错误:

混合了 .netstandard2.0 和 .netframework47 的 DLLs 在 nuget 包中 – .netstandard 不可用

包本身包含了所有 3 个 DLLs,如预期所示:

混合了 .netstandard2.0 和 .netframework47 的 DLLs 在 nuget 包中 – .netstandard 不可用

但是当我构建项目并检查 bin 文件夹时,NetStandardClass DLL 不在其中:

混合了 .netstandard2.0 和 .netframework47 的 DLLs 在 nuget 包中 – .netstandard 不可用

英文:

First of all I don't know if what I'm doing is fundamentally the wrong idea, so the answer could be to just not do this, but here goes..

I have a package that I'm creating from a .nuspec file, in its "files" section it contains references to both .net standard and .net framework DLLs. It also has dependencies on both .netstandard20 and .netframework47.

The reason behind this being that the legacy libraries are written in framework, and the new ones are being written in standard.

We have a consuming project (actually, several), written in .netframework 4.7 that needs to address both sets of DLLs. I have changed the project to use PackageReference rather than packages.config, and
Visual Studio shows that the package is being referenced (rather than the individual namespaces) in the References section. When I build, the .netframework DLLs get copied into the bin folder, but not the .netstandard DLL.

I've created a scratch project to isolate the issue, and I'm seeing the same there as well. The project basically just refuses to acknowledge the standard one. If I add a using statement into a class with a type from the .netstandard DLL it just puts a red squiggly under it and tells me it doesn't exist in the namespace.

It's been suggested that I break the .netstandard DLLs out into their own NuGet package, is that the answer or am I missing something?

Here's some examples..

The .nuspec file:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;package &gt;
  &lt;metadata minClientVersion=&quot;2.5&quot;&gt;
    &lt;!-- other tags removed for brevity --&gt;
    &lt;dependencies&gt;
      &lt;group targetFramework=&quot;.NETStandard2.0&quot;&gt;&lt;/group&gt;
      &lt;group targetFramework=&quot;.NETFramework4.7&quot;&gt;
        &lt;dependency id=&quot;NLog&quot; version=&quot;3.1.0.0&quot; /&gt;
      &lt;/group&gt;
    &lt;/dependencies&gt;
  &lt;/metadata&gt;
  &lt;files&gt;
    &lt;file src=&quot;..\Src\MyProj1\bin\Release\netstandard2.0\NetStandardClass.dll&quot; target=&quot;lib\netstandard2.0&quot; /&gt;
    &lt;file src=&quot;..\Src\MyProj2\bin\Release\NetFrameworkClass1.dll&quot; target=&quot;lib\net47&quot; /&gt;
    &lt;file src=&quot;..\Src\MyProj3\bin\Release\NetFrameworkClass2.dll&quot; target=&quot;lib\net47&quot; /&gt;
  &lt;/files&gt;
&lt;/package&gt;

The package is referenced as a package, not the individual types within it:

混合了 .netstandard2.0 和 .netframework47 的 DLLs 在 nuget 包中 – .netstandard 不可用

If I try to manually add a using statement referencing the NetStandardClass's namespace it's marked as an error

混合了 .netstandard2.0 和 .netframework47 的 DLLs 在 nuget 包中 – .netstandard 不可用

The package itself contains all 3 DLLs as expected:

混合了 .netstandard2.0 和 .netframework47 的 DLLs 在 nuget 包中 – .netstandard 不可用

Yet when I build the project and inspect the bin folder, the NetStandardClass DLL is not there:
混合了 .netstandard2.0 和 .netframework47 的 DLLs 在 nuget 包中 – .netstandard 不可用

答案1

得分: 1

> 已经有建议将 .netstandard DLLs 拆分到它们自己的 NuGet 包中,这是答案,还是我漏掉了什么?

基本上,是的,拆分包是答案。另一个可能性是将 netstandard 组件移动到 net47 文件夹中,或者将 net47 组件移动到 netstandard2.0 文件夹中,但无论哪种方式都可能出现问题。虽然解决方案是重新编译所有的组件,使它们都使用相同的目标框架,但这也有其自身的问题。

如果您已经阅读了 NuGet 文档,并得出结论认为您正在尝试的内容应该可以工作,请告诉我是哪些文档让您相信了这一点,这样我就可以更新文档并尝试消除困惑。

关于为什么 NuGet 支持一个包含多个目标框架文件夹的包的首要问题是,一个包可能希望在可能的情况下使用新的框架特性,但同时支持使用旧框架的包的用户。因此,包的作者需要多个版本的他们的程序集,具体取决于哪个版本与用户的项目兼容。因此,关键在于 NuGet 需要根据项目使用的目标框架标识(TFM)从包中选择资产。NuGet 实际执行资产选择的方式如下:

NuGet 查看包中存在哪些 TFM 文件夹,以获取包支持的 TFM 列表。通常会查找 lib/&lt;tfm&gt;/ref/&lt;tfm&gt; 文件夹,但 contentFiles/&lt;tfm&gt;build/&lt;tfm&gt; 文件也可能相关。请注意,它不会查看任何文件名。lib/net47/*.dlllib/netstanard2.0/*.dll 下存在哪些程序集尚未考虑在内。

一旦获得了项目 TFM 的这个包 TFM 列表,它会查看项目 TFM,并选择“最佳” TFM。对于多目标的 SDK 样式项目,它会针对每个项目 TFM 执行此操作。所谓的“最佳” TFM 意味着相同的“系列”(net* 项目始终选择 net* 资产,如果可用。仅当不存在 net* 程序集时,netstandard 兼容的 .NET Framework TFM 才会寻找 netstandard* 资产)。

选择了项目的 TFM 的包 TFM 后,NuGet 会选择所有类似于 lib/&lt;tfm&gt;/*.dllref/&lt;tfm&gt;/*.dllcontentFiles/&lt;tfm&gt;/&lt;lang&gt;/*build/&lt;tfm&gt;/&lt;package_id&gt;.&lt;props|targets&gt; 等文件。

因此,您可以看到,如果您的包包含 lib/net47/assembly1.dlllib/netstandard2.0/assembly2.dll,NuGet 将只会选择其中的一个程序集,而不会同时选择两个,具体取决于 net47 或 netstandard2.0 是否与项目更兼容。

尽管如果 NuGet 对每个 TFM 进行选择,而不是首先选择 TFM,然后仅选择该文件夹中存在的程序集,可能对您似乎是可取的,但考虑当一个包向旧的 TFM 添加附加的助手实用程序以“填充”包在新的 TFM 中使用的特性时。这个助手实用程序在新的 TFM 中是不需要的,所以 NuGet 选择它会是不合适的。

NuGet 团队建议为每个程序集创建一个包,这样问题就不会出现,因为 NuGet 将会根据包来进行资产选择,假设每个包都被正确地编写,一切都会被正确地选择。如果您坚持将所有程序集捆绑在一个单独的包中,根据我上面的描述,我希望您可以看出您需要将所有程序集放在一个单独的 TFM 文件夹中,但由于不同的程序集针对不同的 TFM 进行编译,可能会出现问题,特别是如果一些开发人员使用不支持 .NET Standard 的旧版本 Visual Studio。我非常强烈建议至少为每个 TFM 创建一个包,或者重新编译所有程序集以使用相同的 TFM。

英文:

> It's been suggested that I break the .netstandard DLLs out into their own NuGet package, is that the answer or am I missing something?

Basically, yes, splitting the package is the answer. Another possibility is to move the netstandard assemblies into the net47 folder, or maybe the net47 assemblies into the netstandard2.0 folder, but either way has potential for problems. Although solution is to recompile all your assemblies so they all use the same target framework, but that also has its own issues.

If you had read the NuGet docs and came to the conclusion that what you're attempting should work, please point me to which docs lead you to believe that, so I can update the docs and try to remove the confusion.

The first thing to understand about why NuGet supports a package having multiple target framework folders is because a package might want to use new framework features where possible, but have support for users of the package using older frameworks. Therefore, the package author needs multiple versions of their assembly, depending on which one is compatible with their users project. So, the point is that NuGet needs to select assets from the package depending on which target framework moniker (TFM) the project uses. The way NuGet actually does asset selection is as follows:

NuGet looks are which TFM folders exist in the package, to get a list of TFMs that the package supports. Generially it looks for lib/&lt;tfm&gt;/ and ref/&lt;tfm&gt; folders, but contentFiles/&lt;tfm&gt; and build/&lt;tfm&gt; files might be relevant as well. Notice it doesn't look at any filenames. Which assemblies exist under lib/net47/*.dll or lib/netstanard2.0/*.dll are not yet considered.

Once it has this list of package TFMs, it looks at the project TFM, and it selects the "best" TFM. For SDK style projects that multi-target, it does this once per project TFM. "Best" TFM means same "family" (net* projects always choose net* assets, if available. only when no net* assemblies exist does netstandard compatible .NET Framework TFMs look for netstandard* assets).

Once a package TFM is selected for the project's TFM, then NuGet selects all the files like lib/&lt;tfm&gt;/*.dll, ref/&lt;tfm&gt;/*.dll, contentFiles/&lt;tfm&gt;/&lt;lang&gt;/*, build/&lt;tfm&gt;/&lt;package_id&gt;.&lt;props|targets&gt;, and so on.

So, you can see that if your package contains lib/net47/assembly1.dll and lib/netstandard2.0/assembly2.dll, NuGet will only ever select one of the two assemblies, never both, depending on if net47 or netstandard2.0 is more compatible with the project.

Although it might seem desirable for you if NuGet did TFM selection per TFM, rather than selecting TFM first and then selecting only the assemblies that exist in that folder, consider when a package adds an additional helper utility to "polyfill" old TFMs with features that the package uses in newer TFMs. This helper utility is not needed for newer TFMs, so it would be undesirable for NuGet to select it.

The NuGet team suggests creating one package per assembly, in which case this problem never would have occured, because NuGet would have done asset selection per package, and assuming each package was authored correctly, everything just selects selected correctly. If you insist on bundling all the assemblies in a single package, from my description above I hope you see you need to put all the assemblies in a single TFM folder, but since different assemblies were compiled against different TFMs, there's potential for problems, particularly if some developers are using older versions of Visual Studio that might not support .NET Standard. I very strongly recommend at the very least creating one package per TFM, or recompiling all the assemblies to use the same TFM.

huangapple
  • 本文由 发表于 2020年1月6日 23:54:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/59615130.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定