Skip to content

Instantly share code, notes, and snippets.

@yishaigalatzer
Created February 24, 2016 21:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save yishaigalatzer/8e9912e01ed4b87762a4 to your computer and use it in GitHub Desktop.
Save yishaigalatzer/8e9912e01ed4b87762a4 to your computer and use it in GitHub Desktop.
---
layout: post
title: NuGet ContentFiles Demystified
author: Jeffrey T. Fritz
comments: true
---
In NuGet 3.3, the `contentFiles` feature was introduced to support project.json managed projects and packages that are indirectly referenced in a project. This was an important change because it brings the ability to deliver static files, .pp file transforms, and language specific code into a project. In this post, we'll explore how to make use of this feature and show some samples of how to make the most of it in your projects.
## Definition
Let's start with a quick definition. ContentFiles in NuGet are static files that the NuGet client will make available through the project.lock.json file to a project for inclusion in the project. There are three different types of files that can be included as a contentFile:
* Language specific files (.cs, .vb, .fs) that are directly included in a project
* Language specific .pp transform files that are transformed and their output is included in the project for compilation
* Other static files (text files, image files, etc) that can be embedded in a project or added for use during development and not included when the project is compiled
ContentFiles are placed in a NuGet package in the `/contentFiles` folder and their capabilities are defined in the `/package/metadata/contentFiles` element inside the nuspec document. Attributes are defined for these files that are passed to the project system to indicate how the files should be used in a project.
## First Example - Include a Branding Image
A first example that we can look at would be to include a png of your organization so that all applications have the same logo in the 'About' page. In the case of NuGet, we would want to use the same .NET Foundation logo everywhere. To build a package to deliver this logo, we could create a `contentFiles` folder on disk and a nuspec to define the package. Our disk layout would start off like the following:
c:\dev\ContentFilesExample\ContentFilesExample.nuspec
c:\dev\ContentFilesExample\contentFiles
When placing content into the `contentFiles` folder, we have some options to help steer the project that uses the content. There are two folder levels that are defined under contentFiles to categorize our content:
* Language (vb, cs, fs)
* Target Framework Moniker or TFM (net35, wp81, etc)
Either of these can be replaced with the catch-all `any` name in order to deliver content to all languages or framework types. In the case of our logo, we would like it to be delivered for all languages and for any framework type therefore we will place the logo in the `contentFiles\any\any` folder. To make it even clearer that this is an image, I'll add an images folder to the hierarchy and our physical file structure will look like this:
c:\dev\ContentFilesExample\ContentFilesExample.nuspec
c:\dev\ContentFilesExample\contentFile\any\any\images\dnf.png
Next, we need to author the nuspec appropriately to deliver this image with an EmbeddedResource action. A minimum nuspec document for this package may look like the following:
```xml
<?xml version="1.0"?>
<package>
<metadata minClientVersion="3.3.0">
<id>ContentFilesExample</id>
<version>1.0.0</version>
<authors>nuget</authors>
<owners>nuget</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>A content v2 example package.</description>
<tags>contentv2 contentFiles</tags>
<!-- Build actions for items in the contentFiles folder -->
<contentFiles>
<!-- Include Assets as Content -->
<files include="**/images/*.*" buildAction="EmbeddedResource" />
</contentFiles>
</metadata>
</package>
```
Notice the file-globbing pattern on the `files/@include` attribute. We have a lot of flexibility to reference groups of files and define features for them using this markup.
## Adding files from other locations
The contentFiles elements in the nuspec are pointers to files that exist inside the package. We can use the [standard NuGet files element](http://docs.nuget.org/Create/NuSpec-Reference#specifying-files-to-include-in-the-package) to move items from outside of the package folder hierarchy into the package. Lets start using that markup to add a CS file into the package. I can add a file called `ExampleInternals.cs` to the root of my package folder so that the file structure on disk is:
c:\dev\ContentFilesExample\ContentFilesExample.nuspec
c:\dev\ContentFilesExample\ExampleInternals.cs
c:\dev\ContentFilesExample\contentFile\any\any\images\dnf.png
My nuspec will now be modified to contain the following:
```xml
<?xml version="1.0"?>
<package>
<metadata minClientVersion="3.3.0">
<id>ContentFilesExample</id>
<version>1.0.1</version>
<authors>nuget</authors>
<owners>nuget</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>A content v2 example package.</description>
<tags>contentv2 contentFiles</tags>
<!-- Build actions for items in the contentFiles folder -->
<contentFiles>
<!-- Include Assets as Content -->
<files include="**/images/*.*" buildAction="EmbeddedResource" />
<files include="cs/**/*.*" buildAction="Compile" />
</contentFiles>
</metadata>
<files>
<file src="contentFiles\**" target="contentFiles" />
<file src="ExampleInternals.cs" target="contentFiles\cs\any" />
</files>
</package>
```
Notice that we now have defined all of the files that are included in the package outside of the metadata element. Since we started declaring the files to include in the nuspec, all files must be declare in this way and the convention of just referencing the location on disk is no longer observed in this mode.
## Other options
The files that are referenced by the contentFiles element in NuSpec have four attributes that can be set on them:
* `include` OR `exclude` - The pattern or filename that should be included or excluded in the package
* `buildAction` - the action the compiler is recommended to take. Possible values include: `None`, `Compile`, `EmbeddedResource`. The default value if this attribute is not provided is `Compile`
* `copyToOutput` - should these files be copied to the output folder? The default value is false.
* `flatten` - Should the files be all delivered to the root folder of the project or should they keep the folder structure that they were packaged in. The default value is false, which indicates they should create (if necessary) and keep the same structure they have after the TFM folder in the pacakge.
## Summary
ContentFiles in NuGet packages allows the package author to deliver more information to their consumers about the content that is delivered to a project.json managed project. The package author can help steer the compiler to provide settings for the files delivered to ensure that they are used properly by the project that installed the package. You can read more about the [contentFiles feature definition in the NuGet docs](http://docs.nuget.org/Create/NuSpec-Reference#contentfiles-with-visual-studio-2015-update-1-and-later).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment