31

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

I believe this is related:

Marcus
  • 8,230
  • 11
  • 61
  • 88

5 Answers5

39

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 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).

Ian Kemp
  • 28,293
  • 19
  • 112
  • 138
  • 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. " – Seabizkit May 12 '20 at 12:36
  • +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. – OutstandingBill Jun 29 '20 at 11:47
  • 3
    Thanks, this is awesome, could be from me. :D ([Here](https://github.com/teroneko/Teronis.DotNet/tree/develop/src/MSBuild/Packaging/ProjectBuildInPackage) you find the source code of the lines above. I decided to deliver it as [package](https://www.nuget.org/packages/Teronis.MSBuild.Packaging.ProjectBuildInPackage/) too) – Teneko Oct 16 '20 at 06:48
  • 2
    @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. – Ian Kemp Oct 16 '20 at 13:31
  • Marking as correct, since there is still no way and probably never will be. – Marcus Dec 10 '21 at 17:56
  • 1
    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.` – riezebosch Sep 26 '22 at 16:41
  • `PrivateAssets="all"` was very confusing to me, but read it like this, **Include all private assets** in the NuGet package for the given project reference. – Jess Feb 24 '23 at 22:22
8

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

GlennSills
  • 3,977
  • 26
  • 28
  • 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. – OutstandingBill Jun 29 '20 at 12:46
  • 2
    This approach worked for me in the case where I need more control inside the package. just note that having `./relative/path/to.nuspec` in `` in `.csproj` allows us to use `dotnet pack` command with the `.nuspec` file. – Yas Ikeda Jul 08 '20 at 21:23
7

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.

gigi
  • 796
  • 9
  • 21
  • 1
    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. – Teneko Mar 29 '21 at 07:04
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

Efrain
  • 3,248
  • 4
  • 34
  • 61
  • 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? – Immortal Blue Aug 25 '22 at 06:14
  • 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? – Efrain Sep 06 '22 at 18:13
-5

I hope this will help you.

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

or your command whatever.

Hayrullah Cansu
  • 262
  • 5
  • 14