0
0
Lập trình
Admin Team
Admin Teamtechmely

Khắc Phục Lỗi NU5019 Trong Dự Án .NET Đa Mục Tiêu

Đăng vào 7 giờ trước

• 4 phút đọc

Giới thiệu

Khi làm việc với các dự án .NET đa mục tiêu, bạn có thể gặp phải lỗi NU5019: File not found khi cố gắng tạo gói NuGet. Lỗi này thường xảy ra do biến $(TargetFramework) không được giải quyết đúng cách trong quá trình đóng gói. Trong bài viết này, tôi sẽ hướng dẫn bạn cách khắc phục vấn đề này một cách hiệu quả và cung cấp một số mẹo hữu ích khác.

Vấn Đề

Tôi đã làm việc với một giải pháp chứa hai dự án:

  • MyProject.Core (dự án VB.NET, đa mục tiêu net47net9.0)
  • MyProject.Utils (dự án C#, cũng đa mục tiêu net47net9.0)

Mục tiêu của tôi là tạo một gói NuGet duy nhất từ dự án VB.NET, bao gồm cả DLL của dự án VB.NET và C# cho mỗi khung mục tiêu.

Ban đầu, tôi đã thử cách tiếp cận "rõ ràng" trong tệp .vbproj của mình:

xml Copy
<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>

Nhưng khi tôi chạy dotnet pack, tôi nhận được:

plaintext Copy
error NU5019: File not found: 'C:\...\MyProject.Utils\bin\Release\MyProject.Utils.dll'

Nguyên Nhân Gốc

Nguyên nhân của vấn đề là biến $(TargetFramework) không được giải quyết chính xác trong giai đoạn đóng gói ở các kịch bản đa mục tiêu. Thay vì được giải quyết thành net47 hoặc net9.0, nó đã được giải quyết thành một chuỗi rỗng, tạo ra các đường dẫn không hợp lệ như:

bin\Release\MyProject.Utils.dll (thiếu thư mục khung)

Thay vào đó, các đường dẫn đúng là:

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

Giải Pháp: Phương Pháp MSBuild Target

Sau khi thử vài cách tiếp cận, giải pháp hiệu quả nhất là sử dụng một mục tiêu MSBuild tùy chỉnh thay vì các ItemGroups tĩnh. Dưới đây là những gì tôi đã thực hiện:

xml Copy
<Target Name="IncludeAdditionalFiles" BeforeTargets="_GetPackageFiles">
  <ItemGroup>
    <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>

Tại Sao Giải Pháp Này Hiệu Quả

  1. Thời Gian Mục Tiêu: BeforeTargets="_GetPackageFiles" đảm bảo rằng mục tiêu của chúng ta chạy vào đúng thời điểm trong quá trình đóng gói, sau khi xây dựng hoàn tất nhưng trước khi NuGet thu thập các tệp để đóng gói.

  2. Đường Dẫn Khung Rõ Ràng: Thay vì dựa vào biến $(TargetFramework) có vấn đề, chúng ta sử dụng các định danh khung cứng (net47, net9.0).

  3. Không Có Bản Sao: Vì MSBuild tự động bao gồm các DLL đầu ra chính của dự án, chúng ta chỉ cần rõ ràng bao gồm các DLL của dự án C# bổ sung.

Mẹo Hiệu Suất

  • Sử Dụng Cấu Hình Chắc Chắn: Luôn đảm bảo rằng bạn đã cấu hình đúng các đường dẫn đến các tệp DLL của dự án.
  • Kiểm Tra Trước Khi Đóng Gói: Trước khi chạy dotnet pack, hãy kiểm tra xem tất cả các tệp cần thiết đã có trong thư mục đầu ra chưa.

Các Vấn Đề Thường Gặp

Lỗi MSB4057 GetTargetPath

Trong quá trình làm việc, tôi cũng gặp phải lỗi MSB4057: The target "GetTargetPath" does not exist in the project. Điều này xảy ra khi sử dụng các dự án kiểu SDK được tham chiếu bởi các dự án khác (nhất là các trang web ASP.NET).

Giải pháp là thêm mục tiêu này vào bất kỳ dự án nào gặp lỗi:

xml Copy
<Target Name="GetTargetPath" Returns="@(_FakeOutputPath)">
  <ItemGroup>
    <_FakeOutputPath Include="$(MSBuildProjectDirectory)\$(OutputPath)\$(_InstallerTargetFramework)\$(AssemblyName).dll" />
  </ItemGroup>
</Target>

Kết Quả

Sau khi thực hiện các thay đổi này:

dotnet pack thành công mà không có lỗi NU5019
✅ Gói chứa tất cả các DLL cho cả hai khung mục tiêu:

  • lib/net47/MyProject.Core.dll
  • lib/net47/MyProject.Utils.dll
  • lib/net9.0/MyProject.Core.dll
  • lib/net9.0/MyProject.Utils.dll ✅ Không có cảnh báo trùng lặp ✅ Gói NuGet duy nhất với các phụ thuộc được gộp lại

Những Điều Cần Lưu Ý

  1. Đừng dựa vào $(TargetFramework) trong quá trình đóng gói ở các kịch bản đa mục tiêu - nó có thể không được giải quyết như mong đợi.

  2. Sử dụng các mục tiêu MSBuild cho việc bao gồm tệp động thay vì các ItemGroups tĩnh khi xử lý các yêu cầu đóng gói phức tạp.

  3. Thời gian của các mục tiêu MSBuild là quan trọng - BeforeTargets="_GetPackageFiles" là thời điểm tốt nhất cho các tùy chỉnh đóng gói.

  4. Các dự án đa mục tiêu cần xử lý đặc biệt khi bạn muốn gộp các đầu ra từ nhiều dự án.

Các Cách Tiếp Cận Thay Thế Được Xem Xét

Trước khi quyết định giải pháp này, tôi đã thử:

  • Các ItemGroups đặc thù theo khung với điều kiện
  • Thời gian mục tiêu khác (BeforeTargets="GenerateNuspec")
  • Sử dụng điều kiện Exists() (thất bại do vấn đề thời gian)

Không có cách nào trong số này hoạt động một cách đáng tin cậy. Cách tiếp cận dựa trên mục tiêu với các đường dẫn khung rõ ràng đã chứng minh là giải pháp vững chắc nhất.

Kết Luận

Bạn đã từng gặp phải các vấn đề tương tự với đóng gói MSBuild chưa? Giải pháp nào đã hiệu quả với bạn? Hãy cho tôi biết trong phần bình luận!

Nếu bài viết này giúp bạn giải quyết vấn đề tương tự, hãy tặng cho nó một ❤️ và xem xét chia sẻ với những người khác có thể đang gặp khó khăn với vấn đề này.

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

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào