同一解决方案中,如何控制NuGet包对另一特定版本包的引用?
我有两个NuGet包项目:Package1和Package2,其中Package2通过项目引用依赖Package1。发布Package2时,项目引用会自动转为Package1的NuGet引用(这是预期行为),但无法控制该依赖的版本——当Package1更新到新的主版本时,Package2会出现报错。
之前尝试同时添加PackageReference和ProjectReference,配置如下:
<ItemGroup> <PackageReference Include="Package1" Version="1.*" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\Package1\Package1.csproj" /> </ItemGroup>
但构建时出现package.lock.json不匹配问题,执行dotnet restore --locked-mode时提示NU1004: The package references have changed。
当前生成的nuspec文件中,Package2的依赖配置为:
<dependency id="Package1" version="<Package2Version>" exclude="Build,Analyzers" />
这意味着只有同时发布两个包并保持版本一致才能正常工作,但存在无变更包也需发布的弊端。我需要控制该依赖版本,使其取值为Package1.csproj中的版本,而非Package2.csproj的版本。
方法1:通过MSBuild属性动态指定依赖版本
在Package2的csproj中,移除重复的PackageReference,只保留ProjectReference,然后添加MSBuild目标读取Package1版本并覆盖依赖配置:
<ItemGroup> <ProjectReference Include="..\Package1\Package1.csproj"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </ProjectReference> </ItemGroup> <Target Name="GetPackage1Version" BeforeTargets="GenerateNuspec"> <GetAssemblyIdentity AssemblyFiles="$(OutputPath)\Package1.dll"> <Output TaskParameter="Assemblies" ItemName="Package1Assembly" /> </GetAssemblyIdentity> <PropertyGroup> <Package1Version>%(Package1Assembly.Version)</Package1Version> </PropertyGroup> <ItemGroup> <PackageReference Update="Package1" Version="$(Package1Version)" /> </ItemGroup> </Target>
该目标会在生成nuspec前,读取Package1编译后的程序集版本,将Package2的Package1依赖版本设置为该值,同时保留项目引用用于本地开发。
方法2:直接修改生成的nuspec文件
添加MSBuild目标,在nuspec生成后直接修改其中的依赖版本:
<ItemGroup> <ProjectReference Include="..\Package1\Package1.csproj" /> </ItemGroup> <Target Name="OverridePackage1DependencyVersion" AfterTargets="GenerateNuspec"> <GetProjectProperty Project="..\Package1\Package1.csproj" PropertyName="Version"> <Output TaskParameter="PropertyValue" PropertyName="Package1Version" /> </GetProjectProperty> <XmlPoke XmlInputPath="$(NuspecFile)" Query="/package/dependencies/group/dependency[@id='Package1']/@version" Value="$(Package1Version)" /> </Target>
此方法通过XmlPoke直接修改生成的nuspec文件,无需额外的PackageReference配置,避免lock文件冲突。
方法3:使用Central Package Management (CPM) 统一版本
若项目基于.NET 6+,可启用集中包管理,统一控制Package1的版本:
- 在解决方案根目录创建
Directory.Packages.props:
<Project> <PropertyGroup> <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally> </PropertyGroup> <ItemGroup> <PackageVersion Include="Package1" Version="$(Package1Version)" /> </ItemGroup> </Project>
- 在Package1的csproj中设置版本:
<PropertyGroup> <Version>2.0.0</Version> <!-- Package1的实际版本 --> </PropertyGroup>
- 在Package2的csproj中配置:
<ItemGroup> <ProjectReference Include="..\Package1\Package1.csproj" /> <PackageReference Include="Package1" /> <!-- 版本由全局配置控制 --> </ItemGroup> <Target Name="SyncPackage1Version" BeforeTargets="Restore"> <GetProjectProperty Project="..\Package1\Package1.csproj" PropertyName="Version"> <Output TaskParameter="PropertyValue" PropertyName="Package1Version" /> </GetProjectProperty> <WriteLinesToFile File="Directory.Packages.props" Lines="<Project> <PropertyGroup> <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally> </PropertyGroup> <ItemGroup> <PackageVersion Include="Package1" Version="$(Package1Version)" /> </ItemGroup> </Project>" Overwrite="true" /> </Target>
该方法通过CPM同步Package1的版本到全局配置,确保Package2的NuGet依赖版本与Package1完全一致。
内容的提问来源于stack exchange,提问作者Ilya Chernomordik

