MSBuild multiple dll in a single NuGet package

This is currently not directly supported by NuGet out of the box. You can follow this GitHub issue for updates.

However, there are a few ways to create such NuGet package.

  1. Use the "Nugetizer 3000"

This is an newly developed tool to build NuGet packages from projects and works by installing the NuGet.Build.Packaging nuget package. You can find some documentation on it on its GitHub wiki page but since it is a very new project, there isn't much documentation or community knowledge around it yet(!) (but the team developing it is very helpful, you could file GitHub issues if you get stuck).

  1. Adding a custom target in the project (2.0.0 tooling / VS 2017 15.3+): Create an item in the csproj that will include the referenced project's output DLL

This approach is very hacky as it relies on an internal MSBuild item that the pack targets use. It works by first marking the <ProjectReference> to not be referenced from the created nuget package like this:

<ProjectReference Include="..\libA\libA.csproj" PrivateAssets="All"/>

Then you can add this to the project to include the generated libA.dll in the nuget package:

<PropertyGroup>
  <TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);IncludeP2PAssets</TargetsForTfmSpecificBuildOutput>
</PropertyGroup>
<Target Name="IncludeP2PAssets">
  <ItemGroup>
    <BuildOutputInPackage Include="$(OutputPath)\testprivatelib.dll" />
  </ItemGroup>
</Target>

Note that this requires you to add all the <PackageReference> items of the referenced project to the project you generate the package from since they would be missing from the generated package since you effectively disabled the transitive reference behaviour.

  1. Create a custom .nuspec file

At the time of writing, this is probably the most "supported" way, but also the most complex. NuGet allows you to disable the automatic generation of the resulting .nuspec file and automatic collection of files by setting the <NuspecFile> property in your project, along with a <NuspecProperties> property that allows you to pass replacement tokens for parsing the .nuspec file.

This works by modifying the project file like this:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netstandard1.4</TargetFramework>
    <NuspecFile>$(MSBuildThisFileDirectory)$(MSBuildProjectName).nuspec</NuspecFile>
  </PropertyGroup>
  <ItemGroup>
    <ProjectReference Include="..\LibB\LibB.csproj" />
  </ItemGroup>

  <Target Name="SetNuspecProperties" BeforeTargets="GenerateNuspec">
    <PropertyGroup>
      <NuspecProperties>$(NuspecProperties);id=$(AssemblyName)</NuspecProperties>
      <NuspecProperties>$(NuspecProperties);config=$(Configuration)</NuspecProperties>
      <NuspecProperties>$(NuspecProperties);version=$(PackageVersion)</NuspecProperties>
      <NuspecProperties>$(NuspecProperties);description=$(Description)</NuspecProperties>
      <NuspecProperties>$(NuspecProperties);authors=$(Authors)</NuspecProperties>
    </PropertyGroup>
  </Target>
</Project>

This will automatically look for a .nuspec file with the same name as the project (somelib.csproj => somelib.nuspec) and pass some properties along to it. The properties are created in a target in order to be able to access fully resolved and defaulted properties like PackageVersion.

The .nuspec file could look like this:

<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
  <metadata>
    <id>$id$</id>
    <version>$version$</version>
    <authors>$authors$</authors>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>$description$</description>
    <dependencies>
      <group targetFramework=".NETStandard1.4">
        <dependency id="NETStandard.Library" version="1.6.1" exclude="Build,Analyzers" />
      </group>
    </dependencies>
  </metadata>
  <files>
    <file src="bin\$config$\netstandard1.4\*.dll" target="lib\netstandard1.4\" />
  </files>
</package>

Note that you must add all referenced NuGet packages as a <dependency> element in the .nuspec file since these are no longer automatically generated from the <PackageReference> items in your project file. Refer to the NuSpec Reference for more details.

I have recently created an example project on GitHub demonstrating the use of a custom .nuspec file for exactly this purpose.


The second option that Martin Ullrich mentioned is the only one that works out of the box with .NET Standard that allows to "Generate NuGet package on build" as an integral part of the build.

However like he mentions it has a "hard coded" dependency on a dll with an exact name that you expect to be there (on the output folder) which might bite you in the future. I've found a better alternative which worked for me in .NET Standard without the need of any other modification on this post.

I'll quote it here for completeness. First you edit your csproj and define the PrivateAssets tag for the reference that you'd like to include:

<ItemGroup>
  <ProjectReference Include="..\ClassLibrary1\ClassLibrary1.csproj">
    <PrivateAssets>all</PrivateAssets>
  </ProjectReference>
</ItemGroup>

Then you add this to your csproj:

<PropertyGroup>
<TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage</TargetsForTfmSpecificBuildOutput>
</PropertyGroup>

<Target Name="CopyProjectReferencesToPackage" DependsOnTargets="ResolveReferences">
    <ItemGroup>
        <BuildOutputInPackage Include="@(ReferenceCopyLocalPaths->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference')->WithMetadataValue('PrivateAssets', 'all'))" />
    </ItemGroup>
</Target>

That post also shows how to include the PDBs in the NuGet package option if necessary (which I omitted here).


Been struggling with the same issue and none of the suggested workarounds worked (https://github.com/NuGet/Home/issues/3891) and I couldn't change the csproj to use the new SDK coming with .netcore.

Luckily the nuget pack command comes with the -IncludeReferencedProjects option (ref: https://docs.microsoft.com/en-us/nuget/tools/cli-ref-pack) which does exactly that: "Indicates that the built package should include referenced projects either as dependencies or as part of the package. If a referenced project has a corresponding .nuspec file that has the same name as the project, then that referenced project is added as a dependency. Otherwise, the referenced project is added as part of the package."

Regardless of the *.nuspec file (not needed here) , add -IncludeReferencedProjects to the pack command and the referenced project dlls will be included along with the nuget dll.

nuget.exe pack yourProject.csproj -IncludeReferencedProjects