Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PackageReference in msbuild\custom-task-code-generation\AppSettingStronglyTyped is not working #6610

Open
1 task done
Tripletri opened this issue Jan 30, 2024 · 4 comments

Comments

@Tripletri
Copy link

Issue description

The approaches used in the AppSettingStronglyTyped example no longer work for using NuGet packages in projects with MSBuild Tasks.
When creating a package containing MSBuild Tasks, you cannot use NuGet packages as in a regular ClassLibrary project; NuGet packages, or more precisely the dlls supplied with them, must be bundled with the final package.

To achieve these goals, AppSettingStronglyTyped uses CopyProjectReferencesToPackage Target:

<Target Name="CopyProjectReferencesToPackage" DependsOnTargets="ResolveReferences">
<ItemGroup>
<!-- The dependencies of your MSBuild task must be packaged inside the package, they cannot be expressed as normal PackageReferences -->
<BuildOutputInPackage
Include="@(ReferenceCopyLocalPaths)"
TargetPath="%(ReferenceCopyLocalPaths.DestinationSubPath)" />
</ItemGroup>
</Target>

However, Microsoft.Extensions.DependencyInjection.dll is not included in the final package.
I expect that after running dotnet package .nupkg will have tasks\netstandard2.0\Microsoft.Extensions.DependencyInjection.dll, but it doesn't. Which leads to an error loading the library during the build:

System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.Extensions.DependencyInjection.Abstractions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'.

Steps to reproduce

Sample to reproduce Tripletri#1, integration tests is falling on this commit.
image

Other thoughts

Since CopyProjectReferencesToPackage use ReferenceCopyLocalPathsReferenceCopyLocalPaths and @(ReferenceCopyLocalPaths) is always empty, this may relate to dotnet/sdk#3662.

As a workaround, I simply commit the external DLLs, reference them with <Reference> and manually copy them at build time.

First of all, I'm interested in how to achieve this use of PackageReference in projects with MSBuild Tasks, especially with multi-targeting, since manually managing dependencies for all target frameworks is a headache.

Thanks in advice

Target framework

  • .NET Standard2.0
dotnet --info output
.NET SDK:
 Version:           8.0.101
 Commit:            6eceda187b
 Workload version:  8.0.100-manifests.0f7d8591

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.19045
 OS Platform: Windows
 RID:         win-x64
 Base Path:   C:\Program Files\dotnet\sdk\8.0.101\

.NET workloads installed:
 Workload version: 8.0.100-manifests.0f7d8591
There are no installed workloads to display.

Host:
  Version:      8.0.1
  Architecture: x64
  Commit:       bf5e279d92

.NET SDKs installed:
  2.1.202 [C:\Program Files\dotnet\sdk]
  2.2.402 [C:\Program Files\dotnet\sdk]
  3.1.426 [C:\Program Files\dotnet\sdk]
  5.0.408 [C:\Program Files\dotnet\sdk]
  6.0.321 [C:\Program Files\dotnet\sdk]
  6.0.418 [C:\Program Files\dotnet\sdk]
  7.0.115 [C:\Program Files\dotnet\sdk]
  7.0.203 [C:\Program Files\dotnet\sdk]
  8.0.100 [C:\Program Files\dotnet\sdk]
  8.0.101 [C:\Program Files\dotnet\sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.All 2.1.30 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.2.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.App 2.1.30 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.2.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.32 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.26 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 7.0.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 7.0.15 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 8.0.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 8.0.1 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 2.0.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.30 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.2.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.32 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.26 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 7.0.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 7.0.15 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 8.0.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 8.0.1 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 3.1.32 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.26 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 7.0.5 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 7.0.15 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 8.0.0 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 8.0.1 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Other architectures found:
  x86   [C:\Program Files (x86)\dotnet]
    registered at [HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\x86\InstallLocation]

Environment variables:
  Not set

global.json file:
  Not found

Learn more:
  https://aka.ms/dotnet/info

Download .NET:
  https://aka.ms/dotnet/download
@horato
Copy link

horato commented Jan 30, 2024

You can somewhat work around this issue by adding this line to .csproj of the nuget project
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

@Tripletri
Copy link
Author

You can somewhat work around this issue by adding this line to .csproj of the nuget project <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

Thanks for the tip. With this approach, Microsoft.Build.Framework.dll, Microsoft.Build.Utilities.Core.dll, etc. are also included, judging by the comments in the example project, we want to avoid this

@horato
Copy link

horato commented Jan 31, 2024

You can somewhat work around this issue by adding this line to .csproj of the nuget project <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

Thanks for the tip. With this approach, Microsoft.Build.Framework.dll, Microsoft.Build.Utilities.Core.dll, etc. are also included, judging by the comments in the example project, we want to avoid this

The README on the project seems a bit outdated. Here's a different version that should address this issue. The trick is to add ExcludeAssets="Runtime" to the Microsoft.Build.Utilities.Core PackageReference
https://github.com/MicrosoftDocs/visualstudio-docs/blob/main/docs/msbuild/tutorial-custom-task-code-generation.md

@Tripletri
Copy link
Author

Yes, seems like a good solution, thanks @horato

Solution

  1. Add <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
  2. Add ExcludeAssets="Runtime" to Microsoft.Build.Utilities.Core
Final .csproj file should look like this:
<PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <version>1.0.0</version>
    <title>AppSettingStronglyTyped</title>
    <authors>John</authors>
    <description>Generates a strongly typed setting class base on a txt file</description>
    <tags>MyTags</tags>
    <copyright>Copyright ©Contoso 2022</copyright>
    <!-- we need the assemblies bundled, so set this so we don't expose any dependencies to the outside world -->
    <GenerateDependencyFile>true</GenerateDependencyFile>
    <TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage</TargetsForTfmSpecificBuildOutput>
    <!-- This property tells MSBuild where the root folder of the package's build assets should be. Because we are not a library package, we should not pack to 'lib'. Instead, we choose 'tasks' by convention. -->
    <BuildOutputTargetFolder>tasks</BuildOutputTargetFolder>
    <!-- NuGet does validation that libraries in a package are exposed as dependencies, but we _explicitly_ do not want that behavior for MSBuild tasks. They are isolated by design. Therefore we ignore this specific warning. -->
    <NoWarn>NU5100</NoWarn>
    <DebugType>embedded</DebugType>
    <IsPackable>true</IsPackable>
    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>

<ItemGroup>
   <PackageReference 
	       Include="Microsoft.Build.Utilities.Core"
		   Version="17.0.0"
       PrivateAssets="all"
       ExcludeAssets="runtime"
 />
   <PackageReference
	       Include="Microsoft.Extensions.DependencyInjection"
		   Version="6.0.0"
       PrivateAssets="all" />
</ItemGroup>

<ItemGroup>
    <!-- These lines pack the build props/targets files to the `build` folder in the generated package.
     By convention, the .NET SDK will look for build\<Package Id>.props and build\<Package Id>.targets
     for automatic inclusion in the build. -->
    <Content Include="build\AppSettingStronglyTyped.props" PackagePath="build\" />
    <Content Include="build\AppSettingStronglyTyped.targets" PackagePath="build\" />
</ItemGroup>

<Target Name="CopyProjectReferencesToPackage" DependsOnTargets="ResolveReferences">
    <ItemGroup>
        <!-- The dependencies of your MSBuild task must be packaged inside the package, they cannot be expressed as normal PackageReferences -->
        <BuildOutputInPackage
           Include="@(ReferenceCopyLocalPaths)"
           TargetPath="%(ReferenceCopyLocalPaths.DestinationSubPath)" />
    </ItemGroup>
</Target>

<!-- This target adds the generated deps.json file to our package output -->
<Target Name="AddBuildDependencyFileToBuiltProjectOutputGroupOutput"
        BeforeTargets="BuiltProjectOutputGroup"
        Condition=" '$(GenerateDependencyFile)' == 'true'">

   <ItemGroup>
      <BuiltProjectOutputGroupOutput
          Include="$(ProjectDepsFilePath)"
          TargetPath="$(ProjectDepsFileName)"
          FinalOutputPath="$(ProjectDepsFilePath)" />
   </ItemGroup>
</Target>

P.S. I don't want to close the issue until the documentation is updated

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants