Skip to content

yer.ac | Adventures of a developer, and other things.

  • About
  • Github
  • Dev.to

yer.ac | Adventures of a developer, and other things.

Blog to keep track of things I am upto

Include both Nuget Package References and project reference DLL using “dotnet pack” ?

October 15, 2019 by yer.ac

Do feel free to provide any comments/feedback to @TheRichCarey on Twitter

Recently I have been trying to generate more Nuget packages for our dotnet core projects, utilizing the dotnet pack command. One issue I have been encountering is that the command was either referencing the required nuget packages, or the project reference DLLs, never both.

The current problem.

If you have Project A which has a project reference to Project B as well as including a nuget package called Package A you would expect the generated package to contain a link to both the required nuget package, and the DLL(s) for Project B, yes? This however is not how the dotnet pack command works.

This issue is widely reported on their repo (I.e. https://github.com/NuGet/Home/issues/3891 ) and unfortunately it seems the developers and the community are in a bit of a disagreement to what is “correct”. The official stance (as I understood it) is that the project references won’t be included as they should be their own packages. This however is not always practical or desired.

The workaround.

Plenty of workarounds have been suggested around Stack Overflow and Github including having a seperate nuspec file, using Powershell to inject things into the generated nupkg and so on…

The solution below worked for me, but of course, YMMV.

In the end I ditched having my own .nuspec file within my project (as per some SO posts) and instead used the CSPROJ (as recommended). Below you can see the required fields for the packaging (version, naming, etc), a reference to a nuget package, and a reference to another project within the solution.

CSProj Snippet of dotnet core project
Snippet of CSPROJ with basic package info filled in.

If you run dotnet pack now, it will generate an appropriately named package which will contain a nuget dependancy on SomeNugetPackage. This can be confirmed by opening the nupkg with an archive tool (7Zip,WinRar, WinZip…) and seeing that the only DLL in the lib folder will be the DLL of the project being packed.

The fix is as follows:

  • Alter the project reference to set the ReferenceOutputAssembly flag to true, and IncludeAssets to the DLL name
<ProjectReference Include="..\ProjectB.csproj">
  <ReferenceOutputAssembly>true</ReferenceOutputAssembly>
  <IncludeAssets>ProjectB.dll</IncludeAssets>
</ProjectReference>  
  • Add the following line into the <PropertyGroup> element
<TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage</TargetsForTfmSpecificBuildOutput>
  • Add new target between <project> tags
<Target DependsOnTargets="ResolveReferences" Name="CopyProjectReferencesToPackage">
    <ItemGroup>
      <BuildOutputInPackage Include="@(ReferenceCopyLocalPaths->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference'))"/>
    </ItemGroup>
  </Target>

So now you end up with something that looks like this

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <Version>1.0.9</Version>
    <Product>MyProduct</Product>
    <id>MyProduct</id>
    <PackageId>MyProduct</PackageId>
    <Authors>Your name</Authors>
    <Company>Company Name</Company>
    <Description>My library</Description>
    <Copyright>Copyright © 2019 MyCompany</Copyright>
    <TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage</TargetsForTfmSpecificBuildOutput>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="SomeNugetPackage" Version="1.2.3"/>  
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\ProjectB.csproj">
      <ReferenceOutputAssembly>true</ReferenceOutputAssembly>
      <IncludeAssets>ProjectB.dll</IncludeAssets>
    </ProjectReference>  
  </ItemGroup>
  <!--Next line is to ensure that dependant DLLS are copied-->
  <Target DependsOnTargets="ResolveReferences" Name="CopyProjectReferencesToPackage">
    <ItemGroup>
      <BuildOutputInPackage Include="@(ReferenceCopyLocalPaths->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference'))"/>
    </ItemGroup>
  </Target>
</Project>
End result CSPROJ. (Click to enlarge)

Now if you run dotnet pack you should see any project reference DLL under the lib folder of the package, and if you inspect the nuspec file inside the package (or upload it to your package repo) you should see the nuget dependencies.

Hopefully this helps someone, as there is a lot of conflicting info around. Please let me know if this would cause any issues!

Share this:

  • Click to share on Twitter (Opens in new window)
  • Click to share on Facebook (Opens in new window)
  • Click to share on LinkedIn (Opens in new window)
  • Click to share on Tumblr (Opens in new window)
  • Click to share on Pinterest (Opens in new window)

Related

Share this:

  • Click to share on Twitter (Opens in new window)
  • Click to share on Facebook (Opens in new window)
  • Click to share on LinkedIn (Opens in new window)
  • Click to share on Tumblr (Opens in new window)
  • Click to share on Pinterest (Opens in new window)

Post navigation

Previous Post:

Setting up a self-hosted build agent for Azure DevOps

Next Post:

Ensuring “dotnet test” TRX & Coverage files end up in SonarQube

15 Commments

  1. Shahar Rave says:
    October 31, 2019 at 2:24 pm

    Very useful, thanks!!!

    Reply
  2. Doug says:
    December 17, 2019 at 7:36 pm

    Any way to also include symbol files for references?

    Reply
    1. yer.ac says:
      December 18, 2019 at 11:57 am

      Hi Doug. For me, I wanted to have a separate package that contained the debug symbols rather than bundle them by default. If you are using the new CSPROJ format this is a one liner luckily!

      If you add the line ` true` into the `` of the CSPROJ it will create a 2nd package named `*.symbols.nupkg` at the same location with the PDB files included. See: https://docs.microsoft.com/en-us/dotnet/core/tools/csproj#includesymbols

      If you don’t want a 2nd package, I believe there is another 1-liner you can do which will include them by default, which is found in this Github issue: https://github.com/NuGet/Home/issues/4142#issuecomment-341867400

      Reply
  3. Jared says:
    January 30, 2020 at 4:13 pm

    Thank You!

    Reply
  4. Chris says:
    March 12, 2020 at 6:25 pm

    This is a lifesaver. I would have spend many hours figuring this out and it’s exactly what I wanted. I owe you a beer!

    Reply
  5. Mattias says:
    March 31, 2020 at 7:23 am

    While the nuget packages now look fine, this messes up my test-projects. They can no longer find any classes residing in any transitive dependencies… :thinking:

    Reply
    1. yer.ac says:
      March 31, 2020 at 7:54 am

      Edited: Inline code is being killed by wordpress!

      Hi Mattias!
      I had a similar issue, in that the transitive references weren’t being included unless they were also packages. This may not be the same thing but hopefully points you in the right direction.

      I ended up doing something like this:


      <Target Name="IncludeSpecificDlls" DependsOnTargets="ResolveReferences">
      <ItemGroup>
      <BuildOutputInPackage Include="$(OutputPath)\Company.Namespace.*.dll" />
      </ItemGroup>
      </Target>

      and then just changing the line on “TargetsForTfmSpecificBuildOutput” to be:

      <TargetsForTfmSpecificBuildOutput>IncludeReferencedDlls;IncludeSpecificDlls</TargetsForTfmSpecificBuildOutput>

      Replacing the name as appropriate, which also accepts wildcards. By doing this you should also get any DLL specified in your end-package lib folder.

      Of course YMMV as I had a very specific scenario to cater for!

      Reply
      1. j5ot1eah says:
        April 8, 2020 at 7:55 pm

        I ran into the same issue with my tests and this didn’t fix it unfortunately. Didn’t feel like messing around with it so I ultimately decided to just publish the referenced project as a separate package. I still appreciate you posting this though! This knowledge is hard to come by otherwise.

        Reply
  6. Chris says:
    April 22, 2020 at 7:12 am

    Hi Mattias and all,

    Thank you for your post above, it looks like it will achieve what I want but I’m getting nuget package build errors as follows that I would appreciate help solving:
    “C:\Program Files\dotnet\sdk\3.1.100\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.targets(143,5): error NETSDK1085: The ‘NoBuild’ property was set to true but the ‘Build’ target was invoked. [C:\folder\MyProjectA.csproj]”

    I have been unable to find what is setting “NoBuild=true”, even setting”GeneratePackageOnBuild=false” produces the same error (There was a bug report around GeneratePackageOnBuild=true, setting NoBuild=true).

    Nuget Package CSProj Below:

    My.Project
    My.Project
    net45;net461;netstandard2.0
    6
    1.0.0
    My Product
    My Company
    Me
    Me
    My Company. All rights reserved.
    My Nuget Package
    $(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage
    true
    true
    My.Project.Core
    false

    NET45;NETFULL

    NET461;NETFULL

    NETCORE;NETSTANDARD;NETSTANDARD2_0

    true
    MyProjectA.dll

    WithMetadataValue(‘ReferenceSourceTarget’, ‘ProjectReference’))”/>

    Thanks in advance.

    Reply
    1. Chris says:
      April 22, 2020 at 7:18 am

      Hi Mattias and all,

      Thank you for your post above, it looks like it will achieve what I want but I’m getting nuget package build errors as follows that I would appreciate help solving:
      “C:\Program Files\dotnet\sdk\3.1.100\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.targets(143,5): error NETSDK1085: The ‘NoBuild’ property was set to true but the ‘Build’ target was invoked. [C:\folder\MyProjectA.csproj]”

      I have been unable to find what is setting “NoBuild=true”, even setting”GeneratePackageOnBuild=false” produces the same error (There was a bug report around GeneratePackageOnBuild=true, setting NoBuild=true).

      Nuget Package CSProj Below:

      My.Project
      My.Project
      net45;net461;netstandard2.0
      6
      1.0.0
      My Product
      My Company
      Me
      Me
      My Company. All rights reserved.
      My Nuget Package
      $(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage
      true
      true
      My.Project.Core
      false

      NET45;NETFULL

      NET461;NETFULL

      NETCORE;NETSTANDARD;NETSTANDARD2_0

      true
      MyProjectA.dll

      true
      MyProjectB.dll

      true
      MyProjectB.dll

      true
      MyProjectC.dll

      true
      MyProjectD.dll

      WithMetadataValue('ReferenceSourceTarget', 'ProjectReference'))"/>

      Thanks in advance.

      Reply
  7. Chris says:
    April 22, 2020 at 7:19 am

    Hi Mattias and all,

    Thank you for your post above, it looks like it will achieve what I want but I’m getting nuget package build errors as follows that I would appreciate help solving:
    “C:\Program Files\dotnet\sdk\3.1.100\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.targets(143,5): error NETSDK1085: The ‘NoBuild’ property was set to true but the ‘Build’ target was invoked. [C:\folder\MyProjectA.csproj]”

    I have been unable to find what is setting “NoBuild=true”, even setting ”GeneratePackageOnBuild=false” produces the same error (There was a bug report around GeneratePackageOnBuild=true, setting NoBuild=true).

    Will Post Nuget Package CSProj Below as a reply.

    Thanks in advance.

    Reply
    1. Chris says:
      April 22, 2020 at 7:21 am

      My.Project
      My.Project
      net45;net461;netstandard2.0
      6
      1.0.0
      My Product
      My Company
      Me
      Me
      My Company. All rights reserved.
      My Nuget Package
      $(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage
      true
      true
      My.Project.Core
      false

      NET45;NETFULL

      NET461;NETFULL

      NETCORE;NETSTANDARD;NETSTANDARD2_0

      true
      MyProjectA.dll

      true
      MyProjectB.dll

      true
      MyProjectB.dll

      true
      MyProjectC.dll

      true
      MyProjectD.dll

      WithMetadataValue(‘ReferenceSourceTarget’, ‘ProjectReference’))”/>

      Reply
  8. Ayane says:
    September 4, 2020 at 6:21 pm

    Hello.
    Very very interesting your post. I’ve been wasting my time looking for options to build a nuget package using CI pipeline in Azure and trying to include all my class libraries into only one package and this solution lighted me up and solved my problem once for all.

    Reply
  9. Pingback: Nuget Packaging Series 1: Including other projects’ output assemblies – Sven Hübner IT
  10. Karthik D V says:
    May 20, 2021 at 3:58 pm

    This is good stuff. I was able to resolve my issue quickly. Thank you for this blog!

    Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Dev.To Profile

Rich's DEV Profile

Tags

agile Azure AzureDevOps Azure Functions ContinuousImprovement Cosmos DB Cypress DevOps docker dotnet ES6 Javascript Mocha NLOG Nuget podcast podgrab PowerShell QNAP SCRUM SonarQube Testing TFS VisualStudio VSCODE VSTS wordpress

Follow me on Twitter

My Tweets
© 2023 yer.ac | Adventures of a developer, and other things. - Powered by Minimalisticky
 

Loading Comments...