GitHub Action中dotnet pack无法找到依赖DLL的问题
问题背景
我有一个要发布为NuGet包的项目,依赖PumlGenerator.Attributes包,需要把这个依赖随我的包一同发布,但不希望用户显式引用它。我的csproj配置如下:
<ItemGroup> <PackageReference Include="PumlGenerator.Attributes" Version="1.2.0" PrivateAssets="all" /> <None Include="$(NuGetPackageRoot)PumlGenerator.Attributes\1.2.0\lib\net9.0\PumlGenerator.Attributes.dll" Pack="true" PackagePath="lib\net9.0" /> </ItemGroup>
本地执行dotnet pack可以成功完成并发布,但通过GitHub Action执行时出现错误:
/usr/share/dotnet/sdk/9.0.101/Sdks/NuGet.Build.Tasks.Pack/build/NuGet.Build.Tasks.Pack.targets(221,5): error : Could not find a part of the path '/github/home/.nuget/packages/PumlGenerator.Attributes/1.2.0/lib/net9.0'.
我的Workflow配置如下:
jobs: merge: container: mcr.microsoft.com/dotnet/sdk:9.0 steps: - name: Checkout code uses: actions/checkout@v4 - name: Build run: dotnet pack -p:Version=${{ github.event.release.tag_name }}
使用的dotnet nuget版本为6.12.2.1。
原因分析
本地环境中,你之前执行过还原或构建操作,PumlGenerator.Attributes包已经被下载到~/.nuget/packages目录,所以dotnet pack能找到对应的DLL。但GitHub Action是全新的容器环境,dotnet pack默认不会自动触发依赖还原,导致目标路径不存在,找不到DLL。
另外,你用硬编码的路径和版本号引用DLL,跨平台环境下路径分隔符也存在兼容问题(Windows用\,Linux容器用/),进一步加剧了路径找不到的问题。
解决方案
1. 先执行依赖还原(快速修复)
在Workflow的dotnet pack命令前,添加dotnet restore步骤,确保依赖包被下载到容器的NuGet缓存目录:
- name: Restore dependencies run: dotnet restore - name: Build and pack run: dotnet pack -p:Version=${{ github.event.release.tag_name }} --no-restore
2. 更可靠的打包方式(推荐)
不要直接引用NuGet缓存目录的DLL,改用MSBuild目标自动获取依赖DLL路径,避免硬编码和跨平台问题。修改csproj配置为:
<ItemGroup> <PackageReference Include="PumlGenerator.Attributes" Version="1.2.0" PrivateAssets="all" /> </ItemGroup> <Target Name="IncludePrivateDependencyInPackage" AfterTargets="ResolveReferences"> <ItemGroup> <Content Include="@(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.NuGetPackageId)' == 'PumlGenerator.Attributes'"> <Pack>true</Pack> <PackagePath>lib\net9.0</PackagePath> <Visible>false</Visible> </Content> </ItemGroup> </Target>
这种方式会在构建时自动找到被复制到输出目录的依赖DLL,无需硬编码路径和版本,跨平台也能正常工作,同时PrivateAssets="all"确保用户不会看到这个依赖。
3. 修复路径分隔符(可选,若坚持原方式)
把路径中的\改为/,或者使用MSBuild的$(PathSeparator)变量适配跨平台:
<None Include="$(NuGetPackageRoot)PumlGenerator.Attributes/1.2.0/lib/net9.0/PumlGenerator.Attributes.dll" Pack="true" PackagePath="lib\net9.0" />
但这种方式依然需要确保依赖已被还原,不如第二种方法可靠。
内容的提问来源于stack exchange,提问作者Gargoyle

