在 nuget 包中混合使用 .netstandard2.0 和 .netframework47 DLL - .netstandard 不可用

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

首先我不知道我在做什么从根本上是错误的想法,所以答案可能是不这样做,但这里是..

我有一个从 .nuspec 文件创建的程序包,在其 "files" 部分中,它包含对 .net 标准和 .net 框架 DLL 的引用。它还依赖于 .netstandard20 和 .netframework47。

这背后的原因是遗留库是用框架编写的,而新库是用标准编写的。

我们有一个使用 .netframework 4.7 编写的消耗性项目(实际上是几个),需要处理两组 DLL。我已将项目更改为使用 PackageReference 而不是 packages.config,并且 Visual Studio 表明在引用部分引用了包(而不是单个命名空间)。当我构建时,.netframework DLL 被复制到 bin 文件夹中,但 .netstandard DLL 没有。

我创建了一个临时项目来隔离问题,我在那里也看到了同样的情况。该项目基本上只是拒绝承认标准的。如果我使用 .netstandard DLL 中的类型将 using 语句添加到 class 中,它只会在其下方放置一个红色波浪线,并告诉我它不存在于命名空间中。

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

这里有一些例子..

.nuspec 文件:

<?xml version="1.0" encoding="utf-8"?>
<package >
  <metadata minClientVersion="2.5">
    <!-- other tags removed for brevity -->
    <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>

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

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

包本身包含预期的所有 3 个 DLL:

然而,当我构建项目并检查 bin 文件夹时,NetStandardClass DLL 不存在:

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?

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

如果您已阅读 NuGet 文档并得出结论认为您的尝试应该有效,请指出哪些文档让您相信这一点,以便我更新文档并尝试消除混淆.

首先要了解为什么 NuGet 支持具有多个目标框架文件夹的包是因为包可能希望尽可能使用新的框架功能,但支持使用旧框架的包的用户。因此,包作者需要多个版本的程序集,具体取决于哪个版本与其用户项目兼容。因此,重点是 NuGet 需要 select 包中的资产,具体取决于项目使用的目标框架名字对象 (TFM)。 NuGet实际做asset selection的方式如下:

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

一旦有了这个包 TFM 列表,它就会查看项目 TFM,它 select 是 "best" TFM。对于多目标的 SDK 样式项目,每个项目 TFM 执行一次。 "Best" TFM 表示相同 "family"(net* 项目总是选择 net* 资产,如果可用。只有当不存在 net* 程序集时,netstandard 兼容的 .NET Framework TFM 才会寻找 netstandard* 资产)。

一旦为项目的 TFM select 编辑了包 TFM,然后 NuGet selects 所有文件,如 lib/<tfm>/*.dllref/<tfm>/*.dllcontentFiles/<tfm>/<lang>/* , build/<tfm>/<package_id>.<props|targets>, 等等。

因此,您可以看到,如果您的程序包包含 lib/net47/assembly1.dlllib/netstandard2.0/assembly2.dll,NuGet 只会 select 两个程序集之一,永远不会同时包含这两个程序集,具体取决于 net47 或netstandard2.0 与项目更兼容

尽管如果 NuGet 对每个 TFM 进行 TFM selection,而不是先 selecting TFM 然后 selecting 仅存在于其中的程序集,这对您来说似乎是可取的文件夹,请考虑当一个包向 "polyfill" 旧的 TFM 添加一个额外的辅助实用程序时,它具有该包在较新的 TFM 中使用的功能。较新的 TFM 不需要此辅助实用程序,因此 NuGet 不希望 select 它。

NuGet 团队建议为每个程序集创建一个包,在这种情况下,这个问题永远不会发生,因为 NuGet 会为每个包完成资产 selection,并且假设每个包都正确编写,一切都只是selects select编辑正确。如果您坚持将所有程序集捆绑在一个包中,根据我上面的描述,我希望您看到您需要将所有程序集放在一个 TFM 文件夹中,但是由于不同的程序集是针对不同的 TFM 编译的,因此可能会出现问题,尤其是如果某些开发人员使用可能不支持 .NET Standard 的旧版本 Visual Studio。我强烈建议至少为每个 TFM 创建一个包,或者重新编译所有程序集以使用相同的 TFM。