Search code examples
msbuildnuget-packagedotnet-cli

MSBuild props file does not get evaluated when imported by a nuget package, but works when manually imported


I have created a number of nuget packages with msbuild targets that help me take care of common boilerplate in my .NET projects. Here I am working on a simple .props file which is aimed to make the copyright information in the compiled assembly and the nuget package consistent.

Currently I am struggling with the fact that this props file does not get respected in all build phases of a target project.

The props file looks roughly like the following (full source code available in github):

<PropertyGroup>
  <CopyrightYearCurrent Condition=" '$(CopyrightYearCurrent)' == '' ">$([System.DateTime]::get_UtcNow().get_Year())</CopyrightYearCurrent>
  <CopyrightYear>$(CopyrightYearCurrent)</CopyrightYear>
  <!-- CopyrightYearSince may be defined externally in the consuming project and is non-mandatory -->
  <CopyrightYear Condition=" '$(Authors)' != '' AND '$(CopyrightYearSince)' != '' ">$(CopyrightYearSince)-$(CopyrightYearCurrent)</CopyrightYear>
</PropertyGroup>

<PropertyGroup>
  <Copyright Condition=" '$(Authors)' != '' AND '$(Copyright)' == '' ">Copyright © $(Authors) $(CopyrightYear)</Copyright>
</PropertyGroup>

<PropertyGroup>
  <AssemblyCompany Condition=" '$(AssemblyCompany)' == '' AND '$(Authors)' != '' ">$(Authors)</AssemblyCompany>
  <AssemblyCopyright Condition=" '$(AssemblyCopyright)' == '' AND '$(Copyright)' != '' ">$(Copyright)</AssemblyCopyright>
</PropertyGroup>

In a target project, I have a DirectoryBuild.props placed in my root directory, where I need to activate the props file.

My goal is, when I run dotnet build, or dotnet pack from the command line, the Copyright-related information from msbuild to propagate both to the assembly attributes, and to the nuget package.

Initially, during the development of the props, I just imported the props file using the MSBuild Import directive into my DirectoryBuild.props, and all was working as expected.

Because the props looked quite generic I decided to create a nuget package out of it so I can reuse it in more than a single project, and maintain it from a central place. Then I replaced the Import of the props file inside of DirectoryBuild with a PackageReference directive.

Now, when I execute dotnet pack, the produced nuget package (and the respective nuspec file which is auto-generated in the obj folder) no longer contain the copyright field. At the same time, the compiled dll files have their copyright information correctly applied.

I have examined the complete msbuild output for both scenarios (using the command dotnet build -pp:msbuild.xml) and there are no significant difference in the import order of the props file from the package vs the manually imported file from Directory.Build.props, and so I am stuck with understanding the observed behaviour.

Here is the output of dotnet --info if it is of any use to someone:

.NET SDK (reflecting any global.json): Version: 5.0.202 Commit: db7cc87d51

Runtime Environment: OS Name: Windows OS Version: 10.0.19042 OS Platform: Windows RID: win10-x64 Base Path: C:\Program Files\dotnet\sdk\5.0.202\

Host (useful for support): Version: 5.0.5 Commit: 2f740adc14

Update

Just to weed out any suspicions, the nuget package is properly built (the name of the package and the targets it imports are the same) and my IDE (JetBrains Rider) correctly detects that the .props file from the nuget package is loaded.

Also, CopyrightYearSince and Authors are defined in my Directory.Build.props before the PackageReference directive.

Update 2

It seems the issue occurs only when generating the automatically produced nuspec file. Every override in a props file of a property that should take part in the nuspec is ignored, however, it is used appropriately in the other build tasks. The problem disapears if the props file is directly referred to, as opposed to being used from a nuget package.


Solution

  • It looks like the issue is more complex, because it happens when cross-targeting projects are involved.

    Thanks to a github issue I got more insight on how the GenerateNuspec task is working with imported msbuild tasks, props and targets, so I came to a solution for my own problem. The details below:

    The use-case where the problematic behavior is observed is because:

    1. My nuget packages containing props and targets only include them under build, but not under the buildCrossTargeting folders.
    2. The linked above issue showed me, that when the project is cross-targeting, the GenerateNuspec flow will only include custom props/targets present in the buildCrossTargeting folder, thus my targets got ignored
    3. When I produced a new nuget package where I used both build and buildCrossTargeting, the issue disappeared.

    Conclusion -- be very careful when creating your own msbuild targets as nuget packages -- scenarios such as cross-targeting projects need special handling!