Skip to content

Feature : Allow project reference DLLs to be added to the parent nupkg for pack target like IncludeReferencedProjects in nuget.exe #3891

Open

Description

@joelverhagen

Steps

  1. dotnet new --type lib two .csproj class libraries: projectA and projectB.
  2. Change <TargetFramework> to <TargetFrameworks> if you don't have dotnet pack fails with project references and <TargetFramework> #3865.
  3. Make projectA have a ProjectReference to projectB.
  4. Add <Type>project</Type> to the <ProjectReference>.
  5. dotnet pack projectA
  6. Open the resulting .nupkg's lib folder

Expected

projectB.dll should be in the .nupkg along with projectA.dll

Actual

projectB is still a package reference, not a DLL included in the package.

Environment

Tried latest dev's pack target.

dotnet --info

.NET Command Line Tools (1.0.0-preview3-004056)

Product Information:
 Version:            1.0.0-preview3-004056
 Commit SHA-1 hash:  ccc4968bc3

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.14393
 OS Platform: Windows
 RID:         win10-x64

UPDATE: Please see workaround posted as comment to see how to add ProjectReferences as DLLs in the package dynamically.

Activity

  1. added this to the 4.0 RC2 milestone on Nov 8, 2016
  2. rrelyea commented on Nov 8, 2016

    @rrelyea
    Contributor

    Please check spec on wiki for planned behavior

  3. joelverhagen commented on Nov 8, 2016

    @joelverhagen
    MemberAuthor

    Spec: https://github.com/NuGet/Home/wiki/Adding-nuget-pack-as-a-msbuild-target

    This doesn't work:

    <TreatAsPackageReference>false</TreatAsPackageReference>

    The output .nuspec still has projectB as a package reference and only one file: projectA.dll under lib.

  4. emgarten commented on Nov 8, 2016

    @emgarten
    Member

    This is a non-trivial feature that hasn't been implemented for RC yet.

    Supporting this will require potentially walking the entire project closure to determine all projects that need to be merged into the package, or reading the assets file and matching the project closure with both the project reference flags and the pack flags found in the project (since it can be set either way).

    This is also impacted by build outputs not flowing transitively to parent projects yet.

  5. joelverhagen commented on Nov 10, 2016

    @joelverhagen
    MemberAuthor

    Plan of action:

    1. Build out some automated tests for pack task to cover basic scenarios and detect regression.
    2. Add the original PackageSpec to the lock/assets file.
    3. Add any missing properties to the assets file pack needs (e.g. path to child project output assemblies).
    4. Update restore (no, not pack) to collapse project references when <TreatAsPackageReference> is true.
    5. Move the PackTask away from looking at child projects. Look at restore's assets file instead.

    This has repercussions on:

    • Restore: basically all of the data pack needs should be collected by restore an put in the assets file. Restore should be the only guy doing a walk.
    • Project/Package duality: what if a child project .csproj has a <Reference>. How is this collapsed?
    • What collapsing occurs? Certainly build artifacts and <PackageReference>... what about <Reference>?
  6. self-assigned this
    on Nov 14, 2016
  7. modified the milestones: 4.0 RC2, 4.0 RC3 on Nov 29, 2016
  8. removed their assignment
    on Dec 7, 2016
  9. joelverhagen commented on Dec 7, 2016

    @joelverhagen
    MemberAuthor

    @rohit21agrawal, I partially got through consuming the assets file from in the pack task:
    https://github.com/joelverhagen/NuGet.Client/tree/jver/3891

    This also has some progress on getting the output DLLs of child projects (using @(ReferenceCopyLocalPaths) MSBuild items).

    This branch is pretty rough so let me know if I can clarify.

  10. rohit21agrawal commented on Dec 9, 2016

    @rohit21agrawal
    Contributor

    As per @rrelyea : #3893 (comment)

    "We don't plan to enable this in dotnet pack / msbuild /t:pack in 4.0 timeframe.
    We'll listen to customer feedback and consider in the future."

  11. 448 remaining items

  12. aetos382 commented on Dec 6, 2024

    @aetos382

    I think the microsoft/CsWin32 repository will be helpful.
    It contains a source generator that depends on the System.Text.Json package.

  13. nathanmascitelli commented on Dec 10, 2024

    @nathanmascitelli

    I've gotten the setup that @ViktorHofer and @DomenPigeon have described setup and its works (thank you!). However one thing I have noticed is that if multiple frameworks are specified using TargetFrameworks then the ref folder does not seem to be populated. Is that happening for anyone else? If so has anyone managed to make this work with multiple frameworks?

  14. ViktorHofer commented on Dec 10, 2024

    @ViktorHofer

    Here's the updated version that work with multiple TargetFrameworks as well:

    <Project Sdk="Microsoft.NET.Sdk">
    
      <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFrameworks>net9.0;net8.0</TargetFrameworks>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);IncludeProjectReferenceDlls</TargetsForTfmSpecificBuildOutput>
        <TargetsForTfmSpecificContentInPackage>$(TargetsForTfmSpecificContentInPackage);IncludeReferenceAssemblies</TargetsForTfmSpecificContentInPackage>
        <NoWarn>$(NoWarn);NU5131</NoWarn>
      </PropertyGroup>
    
      <ItemGroup>
        <ProjectReference Include="..\ReferencedLibrary\ReferencedLibrary.csproj" PrivateAssets="all" />
      </ItemGroup>
    
      <Target Name="IncludeProjectReferenceDlls" DependsOnTargets="BuildOnlySettings;ResolveReferences">
        <ItemGroup>
          <BuildOutputInPackage Include="@(ReferenceCopyLocalPaths->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference')->WithMetadataValue('PrivateAssets', 'all'))"
                                TargetPath="%(ReferenceCopyLocalPaths.DestinationSubDirectory)" />
        </ItemGroup>
      </Target>
    
      <!-- Add a ref folder to the package which only exposes the library so that the referenced class library doesn't get exposed. -->
      <Target Name="IncludeReferenceAssemblies">
        <ItemGroup>
          <TfmSpecificPackageFile Include="$(TargetPath)" PackagePath="ref/$(TargetFramework)" />
        </ItemGroup>
      </Target>
    
    </Project>

    I managed to do it using this as reference:
    https://github.com/dotnet/machinelearning/blob/01c41644edef3d02060b4c8bb841878df3528050/eng/Packaging.targets#L19-L52

    Hehe, that's my code copied from dotnet/runtime ;) I would not recommend using that here if not strictly necessary.

  15. nathanmascitelli commented on Dec 11, 2024

    @nathanmascitelli

    @antonioacg @ViktorHofer thank you both! Works like a charm.

  16. afantyro commented on Jan 6, 2025

    @afantyro

    anyone else getting this error with below solution?
    image

    Here's the updated version that work with multiple TargetFrameworks as well:

    <Project Sdk="Microsoft.NET.Sdk">
    
      <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFrameworks>net9.0;net8.0</TargetFrameworks>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);IncludeProjectReferenceDlls</TargetsForTfmSpecificBuildOutput>
        <TargetsForTfmSpecificContentInPackage>$(TargetsForTfmSpecificContentInPackage);IncludeReferenceAssemblies</TargetsForTfmSpecificContentInPackage>
        <NoWarn>$(NoWarn);NU5131</NoWarn>
      </PropertyGroup>
    
      <ItemGroup>
        <ProjectReference Include="..\ReferencedLibrary\ReferencedLibrary.csproj" PrivateAssets="all" />
      </ItemGroup>
    
      <Target Name="IncludeProjectReferenceDlls" DependsOnTargets="BuildOnlySettings;ResolveReferences">
        <ItemGroup>
          <BuildOutputInPackage Include="@(ReferenceCopyLocalPaths->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference')->WithMetadataValue('PrivateAssets', 'all'))"
                                TargetPath="%(ReferenceCopyLocalPaths.DestinationSubDirectory)" />
        </ItemGroup>
      </Target>
    
      <!-- Add a ref folder to the package which only exposes the library so that the referenced class library doesn't get exposed. -->
      <Target Name="IncludeReferenceAssemblies">
        <ItemGroup>
          <TfmSpecificPackageFile Include="$(TargetPath)" PackagePath="ref/$(TargetFramework)" />
        </ItemGroup>
      </Target>
    
    </Project>
    

    I managed to do it using this as reference:
    https://github.com/dotnet/machinelearning/blob/01c41644edef3d02060b4c8bb841878df3528050/eng/Packaging.targets#L19-L52

    Hehe, that's my code copied from dotnet/runtime ;) I would not recommend using that here if not strictly necessary.

  17. ViktorHofer commented on Jan 6, 2025

    @ViktorHofer

    Please share a minimal repro or a binlog. Hard to say without more data.

  18. afantyro commented on Jan 7, 2025

    @afantyro

    Please share a minimal repro or a binlog. Hard to say without more data.

    Sure, thanks for looking into this for me. This is the repo. WinFormsLibraryA is the entry project which

    • uses a nuget package Microsoft.Extensions.DependencyInjection
    • references project WinFormsLibraryB which uses another nuget package Microsoft.Extensions.Caching.Memory

    Just open it in Visual Studio and pack the WinFormsLibraryA, then you will get this NU1012 issue.
    The expected result is a nuget package that:

    • contains both WinFormsLibraryA and WinFormsLibraryB dll files inside the package
    • the nuspec file inside the package should have 2 PackageReference to both Microsoft.Extensions.DependencyInjection and Microsoft.Extensions.Caching.Memory

    This should work similarly if the chain goes longer eg. I have a 3rd level project WinFormsLibraryC referenced by WinFormsLibraryB and has its own PackageReference

  19. ViktorHofer commented on Apr 17, 2025

    @ViktorHofer

    For others, I got asked about how to make the above work when using the dotnet pack --no-build switch. Basically the following:

    call dotnet build
    call task to sign assemblies using azure cert
    call dotnet pack --no-build --no-restore
    call task to sign packages using azure cert
    

    Here's the updated sample that no works with --no-build:

    <Project Sdk="Microsoft.NET.Sdk">
    
      <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFrameworks>net9.0;net8.0</TargetFrameworks>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);IncludeProjectReferenceDlls</TargetsForTfmSpecificBuildOutput>
        <TargetsForTfmSpecificContentInPackage>$(TargetsForTfmSpecificContentInPackage);IncludeReferenceAssemblies</TargetsForTfmSpecificContentInPackage>
        <NoWarn>$(NoWarn);NU5131</NoWarn>
        <BuildProjectReferences Condition="'$(NoBuild)' == 'true'">false</BuildProjectReferences>
      </PropertyGroup>
    
      <ItemGroup>
        <ProjectReference Include="..\ReferencedLibrary\ReferencedLibrary.csproj" PrivateAssets="all" />
      </ItemGroup>
    
      <Target Name="IncludeProjectReferenceDlls" DependsOnTargets="BuildOnlySettings;ResolveReferences">
        <ItemGroup>
          <BuildOutputInPackage Include="@(ReferenceCopyLocalPaths->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference')->WithMetadataValue('PrivateAssets', 'all'))"
                                TargetPath="%(ReferenceCopyLocalPaths.DestinationSubDirectory)" />
        </ItemGroup>
      </Target>
    
      <!-- Add a ref folder to the package which only exposes the library so that the referenced class library doesn't get exposed. -->
      <Target Name="IncludeReferenceAssemblies">
        <ItemGroup>
          <TfmSpecificPackageFile Include="$(TargetPath)" PackagePath="ref/$(TargetFramework)" />
        </ItemGroup>
      </Target>
    
    </Project>

    Make sure that when you invoke dotnet build and then dotnet pack, to use the same configuration. Ideally pass that in to both calls, i.e. in an CI environment:

    dotnet build -c Release && dotnet pack --no-restore --no-build -c Release

    That's important because dotnet pack defaults to Release while dotnet build defaults to Debug.

  20. ViktorHofer commented on May 15, 2025

    @ViktorHofer

    I finally published this sample into a GH repository: https://github.com/ViktorHofer/NuGetPackSamples/tree/main/samples/PackageWithRefAndAdditionalAssemblies

    Updates:

    • Don't put pdbs into non symbol packages. Put pdbs into symbol packages when using IncludeSymbols=true
    • Put the documentation file .xml into the ref folder when using GenerateDocumentationFile=true
    • Put the compiler generated ref assembly into the ref folder instead of the full assembly. Reduces size and doesn't expose implementation details.

    @afantyro sorry for my late reply - I couldn't get this to work without specifying exact platform versions. Also dependencies from transitive projects don't flow because of the use of PrivateAssets=all. See the README in the sample. I still hope this helps...

  21. added a commit that references this issue on Jun 17, 2025
  22. taipignas commented on Oct 22, 2025

    @taipignas

    I have created nuget package successfully with few of the methods mentioned above, all my dll files are packed inside, but when i am trying to use that nuget package i get an error:
    NU1101: Unable to find package ReferencedPackageB. No packages exist with this id in source(s):

    there is a ReferencedPackageB.dll inside

    Seems like i was able to resolve this.

    1. first issue was that my nuget packages were cached in %userprofile%\.nuget\packages and any changes i made werent reflected in the test app where i was inserting the nuget package.
    2. second issue was obvious and mentioned in multiple examples, i needed the property PrivateAssets="All" which excludes the library from nuspec dependencies.
  23. Saibamen commented on Apr 27, 2026

    @Saibamen
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions