You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Roslyn代码生成器构建:如何将所有依赖项嵌入NuGet包?

问题描述

我正在构建一个Roslyn代码生成器,这类分析器项目有硬性约束:必须将所有依赖项包含在包内,不能存在外部NuGet依赖。

当前项目结构:

  • Generator.csproj(代码生成器项目):依赖Syntax项目
  • Syntax.csproj:依赖System.Text.Json NuGet包
  • 测试项目:引用Generator项目作为分析器,用于运行测试

现有项目文件内容:

Generator.csproj

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <LangVersion>10.0</LangVersion>
    <IsRoslynComponent>true</IsRoslynComponent>
  </PropertyGroup>

  <ItemGroup>
    <ProjectReference Include="..\Syntax\Sytnax.csproj" />
  </ItemGroup>
</Project>

Syntax.csproj

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <LangVersion>10.0</LangVersion>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="System.Text.Json" Version="7.0.3" />
  </ItemGroup>
</Project>

测试项目.csproj

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net6</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <ProjectReference
      Include="..\Generator\Generator.csproj"
      OutputItemType="Analyzer"
      ReferenceOutputAssembly="false" />
  </ItemGroup>
</Project>

需求

  • 将Syntax.dll、System.Text.Json.dll及其所有依赖项,都复制到Generator项目的输出目录,并包含在最终的NuGet包中
  • 测试项目引用Generator时,能自动找到所有依赖项

已尝试方案的局限

为Generator对Syntax的项目引用标记PrivateAssets="all",并添加了如下目标,但仅能处理直接项目依赖,无法包含间接的NuGet包依赖:

<Target Name="CopyProjectReferencesToPackage" DependsOnTargets="BuildOnlySettings;ResolveReferences">
  <ItemGroup>
    <BuildOutputInPackage Include="@(ReferenceCopyLocalPaths->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference')->WithMetadataValue('PrivateAssets', 'All'))" />
  </ItemGroup>
</Target>

解决方案

要同时处理项目依赖和间接NuGet包依赖,需要调整项目配置和打包目标,核心是收集所有需要本地复制的依赖项并包含到包中。

步骤1:调整项目引用的私有资产设置

修改Generator.csproj中的项目引用,确保依赖项会被本地复制:

<ItemGroup>
  <ProjectReference Include="..\Syntax\Syntax.csproj" PrivateAssets="all" />
</ItemGroup>

PrivateAssets="all"确保该项目引用的所有依赖不会作为NuGet包的依赖项对外暴露,而是会被本地复制。

步骤2:添加目标收集所有依赖项并包含到包中

在Generator.csproj中添加如下目标,替换之前的CopyProjectReferencesToPackage:

<Target Name="IncludeAllDependenciesInPackage" DependsOnTargets="ResolveReferences">
  <!-- 收集所有需要本地复制的依赖项(包括项目引用和NuGet包引用) -->
  <ItemGroup>
    <BuildOutputInPackage Include="@(ReferenceCopyLocalPaths)" />
    <!-- 确保依赖项的符号文件也被包含(可选,用于调试) -->
    <BuildOutputInPackage Include="@(ReferenceCopyLocalPaths->Replace('.dll', '.pdb'))" Condition="Exists('%(ReferenceCopyLocalPaths.RootDir)%(ReferenceCopyLocalPaths.Directory)%(ReferenceCopyLocalPaths.Filename).pdb')" />
  </ItemGroup>
</Target>

<!-- 将自定义目标绑定到打包流程 -->
<PropertyGroup>
  <TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);IncludeAllDependenciesInPackage</TargetsForTfmSpecificBuildOutput>
</PropertyGroup>
  • ReferenceCopyLocalPaths包含了所有需要本地复制的依赖项,不管是来自项目引用还是NuGet包引用,完美解决间接依赖的问题
  • 额外添加符号文件的包含逻辑,方便调试(可根据需求移除)

步骤3:确保类库项目复制依赖到输出目录

默认类库项目不会复制依赖到输出,需要在Generator.csproj和Syntax.csproj中添加如下配置,让它们像控制台项目一样复制所有依赖:

<PropertyGroup>
  <!-- 启用依赖复制到输出目录 -->
  <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>

该配置会让项目将所有锁定文件中的依赖项复制到输出目录,确保Generator的输出目录包含所有需要的dll。

步骤4:验证测试项目引用

测试项目的现有配置无需修改,因为它将Generator作为Analyzer引用,会自动从Generator的输出目录加载所有包含的依赖项。


效果验证

  1. 构建Generator项目后,检查其输出目录,应该包含:Generator.dll、Syntax.dll、System.Text.Json.dll及其所有依赖dll
  2. 运行dotnet pack生成NuGet包,解压后查看lib/netstandard2.0目录,所有依赖项都应在其中
  3. 运行测试项目,代码生成器能正常加载所有依赖并工作

内容的提问来源于stack exchange,提问作者Paul Turner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 06:35:17