NuGet ContentFiles

Creating a properly authored NuGet package from a SDK-style .csproj file is easy as long as only the primary output assembly should be packed. But things get tricky when it comes to arbitrary content like text or configuration files that should flow seamlessly into the output folder of consuming projects. The following tricks will help.

Build Action “Content”

First of all, change Build Action from “None” to “Content”.

This corresponds to a Content item within the .csproj file.

Copy to Output Directory “Copy if newer”

You might also want to set Copy to Output Directory to “Copy if newer” so that the file is deployed to the output directory when the project is built.

This corresponds to the CopyToOutputDirectory=”PreserveNewest” metadata within the .csproj file.

Note: Never ever use “Copy always” (which corresponds to CopyToOutputDirectory=”Always”)! This will result in an “unstable” build.

PackageCopyToOutput=”true”

Next you need to set PackageCopyToOutput=”true” directly within the .csproj file (there is no Visual Studio property for this).

Only then will the contentFiles section of the auto-generated .nuspec file have the copyToOutput=”true” attribute set.

So far so good. If you now generate a NuGet package out of your .csproj file using e.g. the dotnet pack command or by setting <GeneratePackageOnBuild>true</GeneratePackageOnBuild>, the content file will be copied to the output directory of a consuming project.

But this does only work for direct PackageReferences. It will fail for transitive dependencies.

ProjectReference PrivateAssets=”analyzers;build”

Here is the trick: To make content files flow seamlessly across transitive dependencies, the intermediate referencing project must set PrivateAssets=”analyzers;build” (or anything that does not include contentFiles) on the ProjectReference.

This is because by contentFiles are treated as a private asset by default. Private means that the data goes only into the immediately referencing project, but does not flow across transitive dependencies.

Set PrivateAssets as shown above will result in the following include attribute inside the dependency element of the resulting .nuspec file:

Note how this includes the ContentFiles value which is otherwise excluded by default.

References

Leave a comment