从 NuGet 包中检索 DocFx 元数据

Retrieve DocFx metadata from NuGet packages

我的产品有多个存储库,每个存储库都作为 NuGet 包分发。我想为 DocFx 建立一个单独的存储库,它从 NuGet 包生成文档。这样,它可以将多个{存储库、项目、包}的文档整合到一个位置,同时还允许独立于包发布周期更新概念文档。

TL;DR: 我能够让 DocFx 根据 NuGet 包中的程序集正确生成参考文档,但它不包含任何 XML 文档(即来自 /// 元数据)。我该如何解决这个问题?详情如下。

源包配置

为此,我首先确保源项目的 csproj 文件已配置为生成 XML 文档作为构建输出的一部分:

<Project>
  <PropertyGroup>
    <GenerateDocumentationFile>true</GenerateDocumentationFile>
  </PropertyGroup>  
</Project>

因此,nupkg 文件正确包含 XML 文档,例如:

/lib/net6.0/{AssemblyName}.xml

此文档随后由例如Visual Studio 使用这些包时的 IntelliSense。

DocFx 配置

然后我通过 docfx.json 配置文件为这些程序集添加了 metadata

{
  "metadata": [
    {
      "src": [
        {
          "files": "bin/Release/net6.0/{AssemblyName}.dll"
        }
      ],
      "dest": "api/{AssemblyName}"
    }
  ]
  …
}

有了这个,DocFx 就可以正确识别命名空间、类型和成员,并为每个生成参考文档。到目前为止,一切顺利!

问题

问题是 DocFx 不包含这些程序集的任何 XML Doc (///) 信息,尽管它们包含在程序包中。我该如何缓解这种情况?

如果您在 metadata 配置中指定程序集,DocFx 将在同一目录 (source) 中查找 XML 文档。但是,问题在于,当您包含 NuGet 引用时,该 XML 文档不会包含在项目的 bin 文件夹中,即使它包含在 NuGet 包中也是如此。因此,虽然 DocFx 能够识别 结构 ,但无法识别 文档 .

TL;DR: 要解决此问题,您可以配置 msbuild 复制 XML 文档到 bin 文件夹,确保 DocFx 可以访问它 ()。详情如下。

背景

当您引用 NuGet 包时,默认情况下,包会被下载、解压缩并缓存在以下位置:

%UserProfile%\.nuget\packages\{Package}\{Version}\

Note: This is obviously a Windows directory; the location will vary by operating system.

这将包括例如

\lib\net6.0\{AssemblyName}.dll
\lib\net6.0\{AssemblyName}.xml

构建 .NET 项目时,{AssemblyName}.dll 会复制到项目的 bin 目录,但不会复制 {AssemblyName}.xml。由于您已指示 DocFx 查看项目的 bin 文件夹,因此它无法收集文档。

天真的解决方法

显而易见的解决方法是直接从 NuGet 缓存获取元数据。这可以通过如下调整 docfx.json 配置轻松实现:

{
  "metadata": [
    {
      "src": [
        {
          "files": "bin/Release/net6.0/{AssemblyName}.dll",
          "src": "C:\Users\{User}\.nuget\packages\{Package}\{Version}\lib\net6.0\"
        }
      ],
      "dest": "api/{AssemblyName}"
    }
  ]
  …
}

当然可以。但它也是一个真正 脆弱的解决方案,对于生产代码不可行。最值得注意的是,DocFx 无法识别 %UserProfile% 别名,因此必须将 {User} 硬编码到配置中。这不仅对每个开发人员都不同,而且在构建服务器上也会不同。这甚至没有考虑非 Windows 环境。

更好的解决方案

鉴于此,更好的解决方案是指示 msbuild 将 XML 文档与程序集一起复制到 bin 文件夹。幸运的是,这很容易,正如 中所讨论的那样。在您的 csproj 文件中,只需添加以下内容:

<Project>
  <Target Name="_ResolveCopyLocalNuGetPkgXmls" AfterTargets="ResolveReferences">
    <ItemGroup>
      <ReferenceCopyLocalPaths Include="@(ReferenceCopyLocalPaths->'%(RootDir)%(Directory)%(Filename).xml')"
      Condition="'%(ReferenceCopyLocalPaths.NuGetPackageId)'!='' and Exists('%(RootDir)%(Directory)%(Filename).xml')" />
    </ItemGroup>
  </Target>
</Project>

这种方法的主要优点是它依赖 msbuild 变量来抽象 NuGet 缓存的位置、包名称、版本号和目标文件夹。因此,这应该适用于任何机器或操作系统。

有了这个,DocFx 将在程序集旁边成功找到 XML 文档,并将其包含在生成的 yml 元数据中。