将DotnetCliTool项目推送到NuGet时项目依赖被识别为包依赖的问题
你遇到的核心问题是:当打包DotnetCliTool类型的NuGet包时,项目引用(ProjectReference)默认会被转换为NuGet包依赖项,但你的MyAppNameSpace.Core和MyAppNameSpace.Common并没有发布到NuGet,所以其他用户引用你的CLI工具时,NuGet会尝试下载不存在的包,导致失败。
要解决这个问题,我们需要把依赖的项目编译产物嵌入到CLI工具的NuGet包中,而不是将它们声明为外部包依赖。具体步骤如下:
1. 修改项目引用的私有资产设置
在CLI项目的csproj中,给每个ProjectReference添加PrivateAssets="All"属性,这样MSBuild就不会将这些项目引用转换为NuGet包依赖,而是将它们的编译产物复制到CLI项目的输出目录:
<ItemGroup> <ProjectReference Include="..\NModelsGenerator.Common\NModelsGenerator.Common.csproj" PrivateAssets="All" /> <ProjectReference Include="..\NModelsGenerator.Core\NModelsGenerator.Core.csproj" PrivateAssets="All" /> </ItemGroup>
2. 确保依赖的DLL被包含到NuGet包的工具目录
Dotnet CLI工具的NuGet包要求所有运行时文件放在tools/{TargetFramework}/any目录下。我们需要添加一个自定义目标,将依赖的DLL复制到这个目录,确保打包时包含它们:
在csproj的末尾添加以下内容:
<Target Name="IncludeDependencyDlls" BeforeTargets="Pack"> <!-- 将依赖项目的输出DLL复制到CLI的输出目录 --> <Copy SourceFiles="$(OutputPath)NModelsGenerator.Common.dll" DestinationFolder="$(OutputPath)" /> <Copy SourceFiles="$(OutputPath)NModelsGenerator.Core.dll" DestinationFolder="$(OutputPath)" /> <!-- 确保这些DLL被包含到NuGet包的tools目录 --> <ItemGroup> <None Include="$(OutputPath)NModelsGenerator.Common.dll" Pack="true" PackagePath="tools/netcoreapp2.0/any" /> <None Include="$(OutputPath)NModelsGenerator.Core.dll" Pack="true" PackagePath="tools/netcoreapp2.0/any" /> </ItemGroup> </Target>
3. 完整修改后的csproj示例
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>netcoreapp2.0</TargetFramework> <AssemblyName>dotnet-nmg</AssemblyName> <Authors>Nabin Karki Thapa</Authors> <Version>1.0.2</Version> <Description> The CLI tool for NModelsGenerator, a visual studio extension to create POCO classes from Database Tables and Views. </Description> <DebugType>portable</DebugType> <Copyright>Nabin Karki Thapa</Copyright> <PackageTags>dotnet cli tool</PackageTags> <PackageType>DotnetCliTool</PackageType> <GeneratePackageOnBuild>True</GeneratePackageOnBuild> <PackageProjectUrl>https://github.com/nabinked/NModelsGenerator</PackageProjectUrl> <PackageLicenseUrl>https://github.com/nabinked/NModelsGenerator/blob/master/LICENSE</PackageLicenseUrl> <RepositoryUrl>https://github.com/nabinked/NModelsGenerator</RepositoryUrl> <RepositoryType>git</RepositoryType> <PackageReleaseNotes>More information is available at https://github.com/nabinked/NModelsGenerator </PackageReleaseNotes> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.Extensions.CommandLineUtils" Version="1.1.1" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\NModelsGenerator.Common\NModelsGenerator.Common.csproj" PrivateAssets="All" /> <ProjectReference Include="..\NModelsGenerator.Core\NModelsGenerator.Core.csproj" PrivateAssets="All" /> </ItemGroup> <Target Name="IncludeDependencyDlls" BeforeTargets="Pack"> <Copy SourceFiles="$(OutputPath)NModelsGenerator.Common.dll" DestinationFolder="$(OutputPath)" /> <Copy SourceFiles="$(OutputPath)NModelsGenerator.Core.dll" DestinationFolder="$(OutputPath)" /> <ItemGroup> <None Include="$(OutputPath)NModelsGenerator.Common.dll" Pack="true" PackagePath="tools/netcoreapp2.0/any" /> <None Include="$(OutputPath)NModelsGenerator.Core.dll" Pack="true" PackagePath="tools/netcoreapp2.0/any" /> </ItemGroup> </Target> <Target Name="PostcompileScript" AfterTargets="Pack" Condition=" '$(IsCrossTargetingBuild)' != 'true' "> <Exec Command="call nugetpush $(Configuration) $(MSBuildProjectDirectory)/bin/$(Configuration)/$(AssemblyName).$(Version).nupkg" /> </Target> </Project>
为什么原来的做法会出错?
默认情况下,MSBuild处理ProjectReference时,会将它们转换为NuGet包依赖项写入.nuspec文件。当你的CLI工具被其他项目通过DotnetCliToolReference引用时,NuGet会尝试下载这些依赖包,但你的Core和Common项目并没有发布到NuGet,因此会出现找不到包的错误。通过设置PrivateAssets="All"并手动包含依赖DLL,我们把这些依赖项变成了CLI工具包的一部分,不需要外部NuGet包支持。
内容的提问来源于stack exchange,提问作者Nabin Karki Thapa

