40

Is there any way to force dotnet pack to include all referenced assemblies (all dependencies in project.json)?

I believe this is related:

6 Answers 6

48

As of 2020 there is no officially supported way to do this. However various people have come up with ways to achieve it, and the current best way is to install a NuGet package prepared by the amazing Teroneko. Then all you need to do is edit your .csproj to update all your project to be flagged with PrivateAssets="all", as per the package README.


If you are unable to install the aforementioned NuGet package, you can achieve the same effect by editing your .csproj to include the following (once again, this was discovered by Teroneko - it's essentially what the NuGet package he created does):

<Project>
  <PropertyGroup>
    <TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage</TargetsForTfmSpecificBuildOutput>
  </PropertyGroup>
  
  <Target Name="CopyProjectReferencesToPackage" DependsOnTargets="BuildOnlySettings;ResolveReferences">
    <ItemGroup>
      <!-- Filter out unnecessary files -->
      <_ReferenceCopyLocalPaths Include="@(ReferenceCopyLocalPaths->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference')->WithMetadataValue('PrivateAssets', 'All'))"/>
    </ItemGroup>

    <!-- Print batches for debug purposes -->
    <Message Text="Batch for .nupkg: ReferenceCopyLocalPaths = @(_ReferenceCopyLocalPaths), ReferenceCopyLocalPaths.DestinationSubDirectory = %(_ReferenceCopyLocalPaths.DestinationSubDirectory) Filename = %(_ReferenceCopyLocalPaths.Filename) Extension = %(_ReferenceCopyLocalPaths.Extension)" Importance="High" Condition="'@(_ReferenceCopyLocalPaths)' != ''" />

    <ItemGroup>
      <!-- Add file to package with consideration of sub folder. If empty, the root folder is chosen. -->
      <BuildOutputInPackage Include="@(_ReferenceCopyLocalPaths)" TargetPath="%(_ReferenceCopyLocalPaths.DestinationSubDirectory)"/>
    </ItemGroup>
  </Target>
</Project>

As with the package, you then mark the depended-upon project reference(s) in your .csproj with PrivateAssets="all", and it Just Works(tm).

Sign up to request clarification or add additional context in comments.

7 Comments

im trying this simply does not work... get the following issues on pipelines " ##[error]Error: The process 'C:\Program Files\dotnet\dotnet.exe' failed with exit code 1 ##[error]An error occurred while trying to pack the files. "
+1 Works for me. I have a solution containing an F# project and a C# wrapper for it (plus some other bits and bobs). Before applying this solution (simple cut/paste) my .nupkg did not contain the F# DLL. After applying this solution, it did. Not sure why dependencies are not considered necessary by the pack command though.
Thanks, this is awesome, could be from me. :D (Here you find the source code of the lines above. I decided to deliver it as package too)
@Teroneko I had no idea you have an account here - I have updated the answer to include your package and also converted the answer to Community Wiki so that I do not get credit for it (I should have done so when I first posted it). If you want, you can post your own answer with a link to your package in order to get deserved reputation from people it helps - if you do so, I will flag this answer to be deleted so that yours is the canonical one.
This doesn't work in combination with a --no-build flag (which is default behavior on AppVeyor) because it invokes a (re)build implicitly because of the DependsOn. dotnet pack -c release -o pack --no-build produces the error error NETSDK1085: The 'NoBuild' property was set to true but the 'Build' target was invoked.
|
11

Another solution to the problem is to create a custom .targets file to include in your projects. You can add some msbuild instructions to include the files that you need in the package. There is some documentation here on how to do it, here a short example

<PropertyGroup Condition="$(PackAsComponent) != ''">
  <TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);CustomBuildOutput</TargetsForTfmSpecificBuildOutput>
  <TargetsForTfmSpecificContentInPackage>$(TargetsForTfmSpecificContentInPackage);CustomContentInPackage</TargetsForTfmSpecificContentInPackage>
</PropertyGroup>

<Target Name="CustomBuildOutput">
  <ItemGroup>
    <BuildOutputInPackage Include="$(OutputPath)*.dll" Exclude="$(TargetPath)" />
    <BuildOutputInPackage Include="$(OutputPath)*.pdb" />
    <BuildOutputInPackage Include="$(OutputPath)*.exe" Exclude="$(TargetPath)" />
  </ItemGroup>
</Target>

<Target Name="CustomContentInPackage">
  <ItemGroup>
    <TfmSpecificPackageFile Include="abc.txt">
    <PackagePath>mycontent/$(TargetFramework)</PackagePath>
    </TfmSpecificPackageFile>
  </ItemGroup>
</Target>

Basically I activate this when I set the PackAsComponent property in my project. This preserve the "dotnet pack" functionality 100% without the need to specify any parameter.

1 Comment

Yep this is for advanced scenarios. Needs a lot of understanding for MSBuild but once you master it you can make a lot of it. Good job.
10

I was looking for this answer and was annoyed when I couldn't find an obvious one. The solution that worked best for me was to create a nuspec, add the list of DLLs I wanted in the nupkg to that spec and then build with dotnet pack. I created an easy sample and readme here - nuget sample app

2 Comments

This approach works for me too (as does Ian Kemp's - I tried them both). To me it feels like a more "proper" way to do it than Ian's answer - you don't have to explain to anybody what all the stuff in the .csproj file is for. Having the information about the dependencies in the .nuspec file feels like a more natural place for it.
This approach worked for me in the case where I need more control inside the package. just note that having <NuspecFile>./relative/path/to.nuspec</NuspecFile> in <PropertyGroup> in .csproj allows us to use dotnet pack command with the .nuspec file.
0

As I've installed Octopus build tools on my build system I use octo pack to create the packages. Although this is basically the same thing as just calling good old nuget.exe.

https://octopus.com/docs/packaging-applications/create-packages/octopus-cli

2 Comments

I assume the behaviour is different though? Otherwise Octo wouldn't help the OP? Your answer should probably try to explain what functional different Octo has which solves the OP?
Yes, to my understanding the "oldschool" tools octo.exe and nuget.exe would basically just zip the bin/debug folder, add some metadata and name the file ".nupkg". However, I don't understand the question in this thread anymore anyway. To achieve what OP is asking, would one not just run dotnet publish with dotnet cli these days?
0

In my case, the suggested solution proposed by Ian Kemp could not work because adding PrivateAssets="all" to my ProjectReference would remove it from the <dependencies> of my package.

I also tried the solution of GlennSills to define a .nuspec file but then I had to manually maintain the <dependencies> section.

The most optimal solution to me was to define everything in the .csproj (no .nuspec). So, I made something like Ian Kemp but I don't need to add PrivateAssets="all".

Here is what I needed to add to my .csproj:

<PropertyGroup>
    <TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage</TargetsForTfmSpecificBuildOutput>
  </PropertyGroup>
  
  <Target Name="CopyProjectReferencesToPackage" DependsOnTargets="BuildOnlySettings;ResolveReferences">    
    <ItemGroup>
      <BuildOutputInPackage Include="$(OutputPath)MyReference.dll" TargetPath=""/>
    </ItemGroup>
  </Target>  

This solution works great with the dotnet pack command.

1 Comment

This does not provide an answer to the question. Once you have sufficient reputation you will be able to comment on any post; instead, provide answers that don't require clarification from the asker. - From Review
-5

I hope this will help you.

nuget pack yournuspecfile.nuspec -properties Configuration=Release -IncludeReferencedProjects

or your command whatever.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.