Nikki Locke
Nikki Locke

Reputation: 2941

How do you add additional files to a NuGet package in Visual Studio 2017?

I recently moved to Visual Studio 2017 Community Edition. It has 2 nice new features:

  1. You don't need to explicitly include your source files in the csproj. It does this automatically.

  2. It can build NuGet packages directly.

I want to package up my open source CodeFirstWebFramework DLL as a NuGet package. As well as including the DLL, the package has to include a whole directory tree of other files (including .js, .tmpl, .css and .md files).

How do I tell Visual Studio that I want this directory tree included in the package?

From what information I have found with extensive searching, and ignoring all the out-of-date information that involves adding files to the csproj, all I could find was to place them in a contentFiles folder, but this does not seem to work.

My project file looks like this:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net45</TargetFramework>
    <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
    <Authors>Nikki Locke</Authors>
    <Company>Trumphurst Ltd</Company>
    <Description>Easy to use web server for building web apps that use sql databases generated from c# classes</Description>
    <Copyright>2017 Trumphurst Ltd.</Copyright>
    <PackageProjectUrl>https://github.com/nikkilocke/CodeFirstWebFramework</PackageProjectUrl>
    <RepositoryUrl>https://github.com/nikkilocke/CodeFirstWebFramework</RepositoryUrl>
    <RepositoryType>Github</RepositoryType>
    <PackageTags>C# SQL Code First Web Server</PackageTags>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Markdig" Version="0.12.1" />
    <PackageReference Include="Mono.Data.Sqlite.Portable" Version="1.0.3.5" />
    <PackageReference Include="mustache-sharp" Version="0.2.10" />
    <PackageReference Include="MySql.Data" Version="6.9.9" />
    <PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
  </ItemGroup>

  <ItemGroup>
    <Reference Include="System.Net" />
    <Reference Include="System.Web" />
  </ItemGroup>

</Project>

Wildly guessing what I might need to do from the conflicting and out-of-date information on the web, I have added the following:

  <ItemGroup>
    <Content Include="contentFiles/**/*.*" copyToOutput="true">
      <IncludeInPackage>true</IncludeInPackage>
    </Content>
  </ItemGroup>

Now the .nupkg file has the contents of the contentFiles folder inside it (in two places, a content folder, and a contentFiles folder).

However, when I install the package in another project, the content files do not appear, although they are listed in the project.assets.json file in the obj folder.

Upvotes: 35

Views: 39590

Answers (6)

codevision
codevision

Reputation: 5520

I did following to simply put content in the Nuget package.

<ItemGroup>
  <Content Include="myContentFolder/**/*.*">
    <Pack>true</Pack>
    <PackagePath>contentFiles\any\any;content</PackagePath>
  </Content>
</ItemGroup>

When I want content of myContentFolder to be inside build output, I simply add <PackageCopyToOutput>true</PackageCopyToOutput>. Like this

<ItemGroup>
  <Content Include="myContentFolder/**/*.*">
    <Pack>true</Pack>
    <PackagePath>contentFiles\any\any;content</PackagePath>
    <PackageCopyToOutput>true</PackageCopyToOutput>
  </Content>
</ItemGroup>

Here code which do this magic. https://github.com/NuGet/NuGet.Client/blob/81a398e094281bcf00634252f0b460faffce3e55/src/NuGet.Core/NuGet.Build.Tasks.Pack/PackTaskLogic.cs#L749-L756

Upvotes: 1

Fabian
Fabian

Reputation: 1190

First, please be aware that you need to put your files either into a content or contentFiles folder depending on how you NuGet package is referenced. See the end of this section.

Basically, if a NuGet project is referenced by package.config file, the files from the content folder of the NuGet package will be copied to the referencing project. If the NuGet package is referenced by PackageReference in the project file, the files from the contentFiles folder within the package will be used. It is recommended to include both.

The structure of the contentFiles folder can be found here. It is possible to specify the language and the framework for the files to be copied.

So in your case:

<ItemGroup>
    <Content Include="contentFiles/**/*.*">
        <Pack>true</Pack>
        <PackagePath>contentFiles\any\any;content</PackagePath>
    </Content>
</ItemGroup>

Upvotes: 8

Nikki Locke
Nikki Locke

Reputation: 2941

I have now changed my project file again, so it now reads:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net45</TargetFramework>
    <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
    <Authors>Nikki Locke</Authors>
    <Company>Trumphurst Ltd</Company>
    <Description>Easy to use web server for building web apps that use sql databases generated from c# classes</Description>
    <Copyright>2017 Trumphurst Ltd.</Copyright>
    <PackageProjectUrl>https://github.com/nikkilocke/CodeFirstWebFramework</PackageProjectUrl>
    <RepositoryUrl>https://github.com/nikkilocke/CodeFirstWebFramework</RepositoryUrl>
    <RepositoryType>Github</RepositoryType>
    <PackageTags>C# SQL Code First Web Server</PackageTags>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Markdig" Version="0.12.1" />
    <PackageReference Include="Mono.Data.Sqlite.Portable" Version="1.0.3.5" />
    <PackageReference Include="mustache-sharp" Version="0.2.10" />
    <PackageReference Include="MySql.Data" Version="6.9.9" />
    <PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
  </ItemGroup>

  <ItemGroup>
    <Reference Include="System.Net" />
    <Reference Include="System.Web" />
  </ItemGroup>

  <ItemGroup>
    <Content Include="contentFiles/**/*.*" copyToOutput="true">
      <IncludeInPackage>true</IncludeInPackage>
      <CopyToOutput>true</CopyToOutput>
      <BuildAction>Content</BuildAction>
      <copyToOutput>true</copyToOutput>
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
  </ItemGroup>

  <ItemGroup>
    <Compile Remove="Phone\**" />
    <EmbeddedResource Remove="Phone\**" />
    <None Remove="Phone\**" />
  </ItemGroup>

</Project>

The contentFiles are now successfully copied into a folder of the same name (i.e. contentFiles) in any project that downloads the NuGet package - not sure which directive worked, but one of them did.

The content is not automatically copied to the project's output folder on compile, unfortunately - suggestions welcome.

Upvotes: 14

Raghubir Singh
Raghubir Singh

Reputation: 227

Addition to above

Below image has my project contentFiles folder structure

Attached code image has my contentFiles folder structure

Design of my .csproj file

my .Csproj file

Upvotes: 0

Raghubir Singh
Raghubir Singh

Reputation: 227

I got the solution.


Below first snippet of code is not sufficient in order to copy files on target application

<ItemGroup>
<Content Include="contentFiles/**/*.*">
    <Pack>true</Pack>
    <PackagePath>contentFiles\any\any;content</PackagePath>
</Content>

Solution-: This will copy files on root folder.

<ItemGroup>
<Content Include="contentFiles/**/*.*">
    <Pack>true</Pack>
    <PackagePath>contentFiles;content</PackagePath>
    <IncludeInPackage>true</IncludeInPackage>
    <CopyToOutput>true</CopyToOutput>
    <BuildAction>Content</BuildAction>
    <copyToOutput>true</copyToOutput>
    <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    <CopyToPublishDirectory>Always</CopyToPublishDirectory>
</Content>

This is working for me. Hope it will work for you.

Upvotes: 3

user3724031
user3724031

Reputation: 245

Wrapping in "Content" and "IncludeInPackage" is good enough to copy the file(s) to the package.

Upvotes: 1

Related Questions