Reputation: 143319
I'm attempting to migrate to using MSBuild Pack support for using .csproj to generate a projects NuGet package where during development local .dll's are used to build the project but they need to be replaced/swapped to reference an external NuGet package in the generated .nuspec when Using MSBuild to "pack" the project.
The closest documented example of this use-case I could find is Replacing one library from a restore graph where it suggests you can replace an external NuGet reference:
<PackageReference Include="Newtonsoft.Json" Version="9.0.1">
<ExcludeAssets>All</ExcludeAssets>
</PackageReference>
Which overrides the package to reference to a local .dll instead:
<Reference Include="Newtonsoft.Json.dll" />
I'm trying to do something similar where the project should build against local .dll's
that were injected as an artifact from a dependent TeamCity/CI build:
<Reference Include="..\..\lib\net45\ServiceStack.Interfaces.dll" />
<Reference Include="..\..\lib\net45\ServiceStack.Text.dll" />
<Reference Include="..\..\lib\net45\ServiceStack.Common.dll" />
But when using ExcludeAssets=All
as per the documentation:
<PackageReference Include="ServiceStack.Common" Version="5.0.0">
<ExcludeAssets>All</ExcludeAssets>
</PackageReference>
The PackageReference doesn't get exported in the generated dependency list, e.g:
<group targetFramework=".NETFramework4.5" />
The closest I've come to getting the preferred behavior is to use ExcludeAssets="compile"
so my local project doesn't build against it, except this behavior also gets exported in the .nuspec:
<group targetFramework=".NETFramework4.5">
<dependency id="ServiceStack.Common" version="5.4.0" exclude="Compile,Build,Analyzers" />
</group>
I only want to avoid building against it locally but have it exported as a normal dependency. The other issue with this approach is that I need it to reference a package that hasn't been published to NuGet yet (as all packages are published in lock-step), e.g:
<!-- v5.5.0 is the new version to publish -->
<PackageReference Include="ServiceStack.Common" Version="5.5.0" ExcludeAssets="compile"/>
The build fails that it can't find the unpublished package:
[NU1102] Unable to find package ServiceStack.Common with version (>= 5.5.0)
Effectively I need someway to "inject" the exact dependencies and version I need in the generated .nuspec so it's included in the generated .nuspec dependency list, e.g:
<group targetFramework="net45">
<dependency id="ServiceStack.Common" version="5.5.0" />
</group>
<group targetFramework=".netstandard2.0">
<dependency id="ServiceStack.Common" version="5.5.0" />
</group>
Is there some way I can manually declare <dependency/>
as above so it's only used when MSBuild/NuGet packs the project? Otherwise is there a way to apply some XML transform to the generated .nuspec so I can manipulate the XML in the .nuspec before it's packed/compressed?
Basically I'm only interested in injecting dependencies when the "pack" target is run so it's ignored/inert in all other targets.
Upvotes: 9
Views: 1899
Reputation: 141
You've probably found another solution for this by now, but I "succeeded" in doing this, by adding some custom targets to the csproj. The solution did leave me with the feeling that maybe I shouldn't have done it.
The steps were
I've modified my fix below so it injects the dependencies mentioned in the post. I've disabled validation here (NoPackageAnalysis=true). You can put it in a .target file and import it from the csproj.
<Project>
<!-- Disable nupkg generation before running pack -->
<Target Name="__DisablePacking" BeforeTargets="GenerateNuspec" Condition="$(NuspecFile) == ''">
<PropertyGroup>
<ContinuePackingAfterGeneratingNuspec>false</ContinuePackingAfterGeneratingNuspec>
</PropertyGroup>
</Target>
<!-- Modify the generated nuspec file and rerun the pack target -->
<Target Name="__EnablePackingAndInjectDependencies" AfterTargets="Pack" Condition="$(NuspecFile) == ''">
<!-- Get the nuspec file name -->
<PropertyGroup>
<_NugetPackOutputAsProperty>@(NuGetPackOutput)</_NugetPackOutputAsProperty>
</PropertyGroup>
<ItemGroup>
<_NugetPackOutputAsItem Remove="@(_NugetPackOutputAsItem)"/>
<_NugetPackOutputAsItem Include="$(_NugetPackOutputAsProperty.Split(';'))" />
</ItemGroup>
<PropertyGroup>
<__NuspecFileName>%(_NugetPackOutputAsItem.Identity)</__NuspecFileName>
</PropertyGroup>
<!-- Create an updated dependencies, with the net46 dependencies copied to a native group -->
<PropertyGroup>
<__NuSpecUpdatedDependencies>
<group targetFramework="net45">
<dependency id="ServiceStack.Common" version="5.5.0" />
</group>
<group targetFramework=".netstandard2.0">
<dependency id="ServiceStack.Common" version="5.5.0" />
</group>
</__NuSpecUpdatedDependencies>
</PropertyGroup>
<!-- Poke them back in -->
<XmlPoke XmlInputPath="$(__NuspecFileName)"
Value="$(__NuSpecUpdatedDependencies)"
Query="/n:package/n:metadata/n:dependencies"
Namespaces="<Namespace Prefix='n' Uri='http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd' />">
</XmlPoke>
<!-- call the pack operation again -->
<PropertyGroup>
<ContinuePackingAfterGeneratingNuspec>true</ContinuePackingAfterGeneratingNuspec>
</PropertyGroup>
<Msbuild
Projects="$(MSBuildProjectFullPath)"
Targets="Pack"
Properties="NuspecFile=$(__NuspecFileName);NoPackageAnalysis=true">
</Msbuild>
</Target>
</Project>
(I was looking to inject a native0.0 framework dependency so my packages could be consumed by c++/cli projects, in case someone should know of an easier way to do it).
Upvotes: 8
Reputation: 769
Interesting question, and when I looked around for answers I found Another discussion in Stackoverflow
Where in one of the comments - there was an indication that the pack command only works with framework projects with 4.6 and above - not 4.5.
The .Net Standard 2.0 has to match 4.6.1 based on this blog entry from Microsoft
Upvotes: 0