DEV Community

assaadfrs
assaadfrs

Posted on

Fixing MSBuild NU5019 Errors in Multi-Targeting .NET Projects: A Complete Guide

TL;DR

Getting NU5019: File not found when packaging multi-targeting .NET projects? The issue is that $(TargetFramework) doesn't resolve properly during dotnet pack. Solution: Use a custom MSBuild target with hardcoded framework paths instead of static ItemGroups with variables.

<Target Name="IncludeAdditionalFiles" BeforeTargets="_GetPackageFiles">
  <ItemGroup>
    <None Include="..\OtherProject\bin\$(Configuration)\net47\OtherProject.dll">
      <Pack>true</Pack>
      <PackagePath>lib\net47\OtherProject.dll</PackagePath>
    </None>
    <None Include="..\OtherProject\bin\$(Configuration)\net9.0\OtherProject.dll">
      <Pack>true</Pack>
      <PackagePath>lib\net9.0\OtherProject.dll</PackagePath>
    </None>
  </ItemGroup>
</Target>
Enter fullscreen mode Exit fullscreen mode

Have you ever encountered the dreaded NU5019: File not found error when trying to create NuGet packages from multi-targeting .NET projects? If you're building projects that target multiple frameworks and want to bundle multiple DLLs into a single package, you've probably run into this frustrating issue.

In this post, I'll walk you through the exact problem I encountered and the solution that finally worked.

The Problem

I was working with a solution containing two projects:

  • MyProject.Core (VB.NET project, multi-targeting net47 and net9.0)
  • MyProject.Utils (C# project, also multi-targeting net47 and net9.0)

My goal was to create a single NuGet package from the VB.NET project that would include both the VB.NET and C# DLLs for each target framework.

Initially, I tried the "obvious" approach in my .vbproj file:

<ItemGroup>
  <None Include="..\MyProject.Utils\bin\$(Configuration)\$(TargetFramework)\MyProject.Utils.dll">
    <Pack>true</Pack>
    <PackagePath>lib\$(TargetFramework)\MyProject.Utils.dll</PackagePath>
  </None>
  <None Include="bin\$(Configuration)\$(TargetFramework)\MyProject.Core.dll">
    <Pack>true</Pack>
    <PackagePath>lib\$(TargetFramework)\MyProject.Core.dll</PackagePath>
  </None>
</ItemGroup>
Enter fullscreen mode Exit fullscreen mode

But when I ran dotnet pack, I got:

error NU5019: File not found: 'C:\...\MyProject.Utils\bin\Release\MyProject.Utils.dll'
Enter fullscreen mode Exit fullscreen mode

The Root Cause

The issue was that $(TargetFramework) doesn't resolve correctly during the packaging phase in multi-targeting scenarios. Instead of resolving to net47 or net9.0, it was resolving to an empty string, creating invalid paths like:

bin\Release\MyProject.Utils.dll (missing framework folder)

Instead of the correct paths:

bin\Release\net47\MyProject.Utils.dll

bin\Release\net9.0\MyProject.Utils.dll

The Solution: MSBuild Target Approach

After trying several approaches, the solution that worked was to use a custom MSBuild target instead of static ItemGroups. Here's what I implemented:

<Target Name="IncludeAdditionalFiles" BeforeTargets="_GetPackageFiles">
  <ItemGroup>
    <!-- Include C# project DLLs only (VB.NET DLLs are included automatically) -->
    <None Include="..\MyProject.Utils\bin\$(Configuration)\net47\MyProject.Utils.dll">
      <Pack>true</Pack>
      <PackagePath>lib\net47\MyProject.Utils.dll</PackagePath>
    </None>
    <None Include="..\MyProject.Utils\bin\$(Configuration)\net9.0\MyProject.Utils.dll">
      <Pack>true</Pack>
      <PackagePath>lib\net9.0\MyProject.Utils.dll</PackagePath>
    </None>
  </ItemGroup>
</Target>
Enter fullscreen mode Exit fullscreen mode

Why This Works

  1. Target Timing: BeforeTargets="_GetPackageFiles" ensures our target runs at the right time during the packaging process, after the build is complete but before NuGet collects the files to pack.

  2. Explicit Framework Paths: Instead of relying on the problematic $(TargetFramework) variable, we use hardcoded framework identifiers (net47, net9.0).

  3. No Duplicates: Since MSBuild automatically includes the primary project's output DLLs, we only need to explicitly include the additional C# project DLLs.

Bonus: Fixing MSB4057 GetTargetPath Errors

While working on this, I also encountered MSB4057: The target "GetTargetPath" does not exist in the project errors. This happens when using SDK-style projects that are referenced by other projects (especially ASP.NET websites).

The fix is to add this target to any project experiencing the error:

<Target Name="GetTargetPath" Returns="@(_FakeOutputPath)">
  <ItemGroup>
    <_FakeOutputPath Include="$(MSBuildProjectDirectory)\$(OutputPath)\$(_InstallerTargetFramework)\$(AssemblyName).dll" />
  </ItemGroup>
</Target>
Enter fullscreen mode Exit fullscreen mode

The Result

After implementing these changes:

dotnet pack succeeds without NU5019 errors

✅ Package contains all DLLs for both target frameworks:

  • lib/net47/MyProject.Core.dll
  • lib/net47/MyProject.Utils.dll
  • lib/net9.0/MyProject.Core.dll
  • lib/net9.0/MyProject.Utils.dll ✅ No duplicate file warnings ✅ Single NuGet package with bundled dependencies

Key Takeaways

  1. Don't rely on $(TargetFramework) during packaging in multi-targeting scenarios - it may not resolve as expected.

  2. Use MSBuild targets for dynamic file inclusion instead of static ItemGroups when dealing with complex packaging requirements.

  3. The timing of MSBuild targets matters - BeforeTargets="_GetPackageFiles" is the sweet spot for packaging customizations.

  4. Multi-targeting projects need special handling when you want to bundle outputs from multiple projects.

Alternative Approaches Considered

Before settling on this solution, I tried:

  • Framework-specific ItemGroups with conditions
  • Different target timing (BeforeTargets="GenerateNuspec")
  • Using Exists() conditions (failed due to timing issues)

None of these worked reliably. The target-based approach with explicit framework paths proved to be the most robust solution.


Have you encountered similar MSBuild packaging issues? What solutions worked for you? Let me know in the comments!

If this post helped you solve a similar problem, give it a ❤️ and consider sharing it with others who might be struggling with the same issue.

Tags: #dotnet #msbuild #nuget #packaging #multitargeting #csharp #vbnet

Top comments (0)