如何打包一个面向.NET Core的可移植.NET库?

21
如何以现代通用的方式打包可移植的.NET库?假设我有一个单一的AnyCPU程序集,我希望将其提供给支持.NET Core API表面的任何.NET平台,例如.NET Framework 4.6和通用Windows平台。
这是一系列关于现代NuGet包作者的问题和答案,特别关注NuGet 3引入的更改。您可能还对以下一些相关问题感兴趣: - 如何打包.NET Framework库? - 如何打包针对通用Windows平台的.NET库? - 如何打包针对.NET Framework和通用Windows平台的.NET库并包含特定于平台的功能? - 如何打包针对通用Windows平台的多架构.NET库? - 如何打包针对通用Windows平台的.NET库,并依赖于Visual Studio扩展SDK?
2个回答

13

本答案基于 打包面向.NET Framework的库所使用的原则。首先请先阅读链接的答案以更好地理解以下内容。

要发布可移植的.NET库,您需要创建一个具有以下结构的NuGet包:

\---lib
    \---dotnet
            MyPortableLibrary.dll
            MyPortableLibrary.pdb
            MyPortableLibrary.XML

所有三个文件都将来自于您的项目的构建输出目录,在 Release 构建配置下。

上述结构中的 dotnet 目录具有特殊含义-它向 NuGet 指示目录中的文件适用于任何平台,只要所有包依赖项与之兼容。因此,您的包可自动在支持所有依赖项的 .NET 平台上使用(例如 .NET Core)。

关键的下一步是确定依赖项列表。由于包管理问题,无法简单地声明对 .NET Core 本身的依赖项(.NET Core 是所有 .NET 平台共享的 API 表面)。相反,您必须手动确定每个 .NET Core 组件的依赖项,并将其添加到 nuspec 文件中。

.NET Core 包的依赖关系检测过程由两个步骤组成:

  1. 确定库引用的 .NET Core 组件。
  2. 确定包含这些组件的 NuGet 包。

Visual Studio 不提供所需的信息。您需要构建库并检查生成的 DLL 文件。以下 PowerShell 脚本将显示 .NET 组件的引用:

Get-ChildItem MyPortableLibrary.dll | % { [Reflection.Assembly]::LoadFile($_.FullName).GetReferencedAssemblies() | % { $_.Name + ".dll" } }

这个命令的输出将会是一个汇编名称列表,例如:

System.Runtime.dll
System.Resources.ResourceManager.dll
System.Numerics.Vectors.dll

获得列表后,打开项目目录中的project.lock.json文件。该文件包含您的项目使用的所有NuGet包的信息。除其他数据外,您还将找到各种JSON块,例如以下内容:

"System.Numerics.Vectors/4.1.0": {
    "dependencies": {
        "System.Globalization": "[4.0.10, )",
        "System.Resources.ResourceManager": "[4.0.0, )",
        "System.Runtime": "[4.0.20, )",
        "System.Runtime.Extensions": "[4.0.10, )"
    },
    "frameworkAssemblies": [
        "mscorlib",
        "System.Numerics"
    ],
    "compile": {
        "ref/net46/System.Numerics.Vectors.dll": {}
    },
    "runtime": {
        "lib/net46/System.Numerics.Vectors.dll": {}
    }
},

这段JSON代码表明“compile”中列出的汇编文件由顶层值中列出的软件包(System.Numerics.Vectors版本4.1.0)提供。使用此信息将每个引用的程序集映射到NuGet软件包。请注意,虽然软件包和程序集名称通常相同,但并非总是如此!

对于任何不属于.NET Core的NuGet软件包,您可以跳过上述流程,因为您已经知道您依赖的确切软件包。这里描述的依赖关系检测逻辑仅在您无法直接在.NET Core上声明依赖项(Microsoft.NETCore软件包)时才需要,原因在上面的链接中有说明。

现在只需根据以下示例在您的nuspec文件中列出所有依赖项:

<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
    <metadata minClientVersion="3.2">
        <id>Example.MyPortableLibrary</id>
        <version>1.0.0</version>
        <authors>Firstname Lastname</authors>
        <description>Example of a portable library with NuGet package dependencies.</description>
        <dependencies>
            <dependency id="System.Numerics.Vectors" version="4.1.0" />
            <dependency id="System.Resources.ResourceManager" version="4.0.0" />
            <dependency id="System.Runtime" version="4.0.20" />
        </dependencies>
    </metadata>
    <files>
        <file src="..\bin\Release\MyPortableLibrary.*" target="lib\dotnet" />
    </files>
</package>

完成了!生成的软件包可以在任何兼容的.NET平台上使用,例如.NET Framework 4.6或通用Windows平台。在创建NuGet软件包之前,请记得使用发布配置构建解决方案。

示例库和相关打包文件可在GitHub上获得。与此答案对应的解决方案是PortableLibrary。

请参阅Lucian Wischik的博客,深入了解操作此类NuGet软件包的逻辑。


2
我觉得这个答案已经过时了,现在应该是lib\nestandard1.5或者1.6等等,我说的对吗? - Omu
@Omu,你是正确的。PowerShell命令不起作用,并显示“Exception calling "LoadFile" with "1" argument(s): "This assembly is built by a runtime newer than the currently loaded runtime and cannot be loaded."。这个答案需要更新或删除。 - David Arno
我同意 - netstandard 是更好的选择,而不是 dotnet。欢迎进行编辑,因为我还没有时间自己审查和重新记录这个主题! - Sander
@DavidAmo PowerShell 命令对我来说运行良好,我正在针对 netstandard1.6 进行目标设置。错误提示让人觉得执行的运行时不是最新的。 - Nate Zaugg

-1

最近几个月,关于如何制作可移植的.NET框架库/ NuGet软件包的最佳方法似乎有很多变动。如果你可以稍等一下,你会想要了解一下.NET Standard。Immo Landwerth在2016年9月写了一篇详细介绍.NET标准的博客文章。.NET Core对.NET Standard 2.0的支持预计将在2017年初到达,与Visual Studio 2017的时间相同,该版本目前处于发布候选人阶段。.NET Standard 2.0将由.NET Framework、.NET Core和Xamarin实现。它还将包括.NET Framework二进制文件的兼容性适配器,这应该使采用更容易。

更新:

Oren Novotny在这个主题上有一篇非常信息丰富的博客文章:Multi-targeting the world: a single project to rule them all。他讨论了.NET Standard以及如何使用Visual Studio 2017进行多目标定位。这篇博客文章是在Visual Studio 2017 RTM之前发布的,但它非常有帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接