project.json and UWP
This document describes the package structure that employs features in NuGet 3+ (Visual Studio 2015 and later). The
minClientVersion property of your
.nuspec can be used to state that you require the features described here by setting it to 3.1.
Adding UWP support to an existing package
If you have an existing package and you want to add support for UWP applications, then you don’t need to adopt the packaging format described here. You only need to adopt this format if you require the features it describes and are willing to work only with clients that have updated to version 3+ of the NuGet client.
I already target netcore45
If you target
netcore45 already, and you don’t need to take advantage of the features here, no action is needed.
netcore45 packages can be consumed by UWP applications.
I want to take advantage of Windows 10 specific APIs
In this case you need to add the
uap10.0 target framework moniker (TFM or TxM) to your package. Create a new folder in your package and add the assembly that has been compiled to work with Windows 10 to that folder.
I don’t need Windows 10 specific APIs, but want new .NET features or don’t have netcore45 already
In this case you would add the
dotnet TxM to your package. Unlike other TxMs,
dotnet doesn't imply a surface area or platform. It is stating that your package works on any platform that your dependencies work on. When building a package with the
dotnet TxM, you are likely to have many more TxM-specific dependencies in your
.nuspec, as you need to define the BCL packages you depend on, such
System.Xml, etc. The locations that those dependencies work on define where your package works.
How do I find out my dependencies
There are two ways to figure out which dependencies to list:
- Use the NuSpec Dependency Generator 3rd party tool. The tool automates the process and updates your
.nuspecfile with the dependant packages on build. It is available via a NuGet package, NuSpec.ReferenceGenerator.
- (The hard way) Use
ILDasmto look at your
.dllto see what assemblies are actually needed at runtime. Then determine which NuGet package they each come from.
project.json topic for details on features that help in the creation of a package that supports the
If your package is intended to work with PCL projects, we highly recommend to create a
dotnet folder, to avoid warnings and potential compatibility issues.
NuGet packages using this format have the following well-known folder and behaviors:
|Build||Contains MSBuild targets and props files in this folder are integrated differently into the project, but otherwise there is no change.|
|Content||Content is not copied automatically into a user's project. Support for content inclusion in the project is planned for a later release.|
|Lib||For many packages the
MSBuild targets and props files in packages
NuGet packages can contain
.props files which are imported into any MSBuild project that the package is installed into. In NuGet 2.x, this was done by injecting
<Import> statements into the
.csproj file, in NuGet 3.0 there is no specific "installation to project" action. Instead the package restore process writes two files
MSBuild knows to look for these two files and automatically imports them near the beginning and near the end of the project build process. This provides very similar behavior to NuGet 2.x, but with one major difference: there is no guaranteed order of targets/props files in this case. However, MSBuild does provide ways to order targets through the
AfterTargets attributes of the
<Target> definition (see Target Element (MSBuild).
Lib and Ref
The behavior of the
lib folder hasn't changed significantly in NuGet v3. However, all assemblies must be within sub-folders named after a TxM, and can no longer be placed directly under the
lib folder. A TxM is the name of a platform that a given asset in a package is supposed to work for. Logically these are an extension of the Target Framework Monikers (TFM) e.g.
dnxcore50 are all examples of TxMs (see Target Frameworks. TxM can refer to a framework (TFM) as well as other platform-specific surface areas. For example the UWP TxM (
uap10.0) represents the .NET surface area as well as the Windows surface area for UWP applications.
An example lib structure:
lib ├───net40 │ MyLibrary.dll └───wp81 MyLibrary.dll
lib folder contains assemblies that are used at runtime. For most packages a folder under
lib for each of the target TxMs is all that is required.
There are sometimes cases where a different assembly should be used during compilation (.NET Reference Assemblies do this today). For those cases, use a top-level folder called
ref (short for "Reference Assemblies").
Most package authors don't require the
ref folder. It is useful for packages that need to provide a consistent surface area for compilation and IntelliSense but then have different implementation for different TxMs. The biggest use case of this are the
System.* packages that are being produced as part of shipping .NET Core on NuGet. These packages have various implementations that are being unified by a consistent set of ref assemblies.
Mechanically, the assemblies included in the
ref folder are the reference assemblies being passed to the compiler. For those of you who have used csc.exe these are the assemblies we are passing to the C# /reference option switch.
The structure of the
ref folder is the same as
lib, for example:
└───MyImageProcessingLib ├───lib │ ├───net40 │ │ MyImageProcessingLibrary.dll │ │ │ ├───net451 │ │ MyImageProcessingLibrary.dll │ │ │ └───win81 │ MyImageProcessingLibrary.dll │ └───ref ├───net40 │ MyImageProcessingLibrary.dll │ └───portable-net451-win81 MyImageProcessingLibrary.dll
In this example the assemblies in the
ref directories would all be identical.
The runtimes folder contains assemblies and native libraries required to run on specific "runtimes", which are generally defined by Operating System and CPU architecture. These runtimes are identified using Runtime Identifiers (RIDs) such as
The following example shows a package that has a purely managed implementation for several platforms, but uses native helpers on Windows 8 where it can call into Windows 8-specific native APIs.
└───MyLibrary ├───lib │ └───net40 │ MyLibrary.dll │ └───runtimes ├───win8-x64 │ ├───lib │ │ └───net40 │ │ MyLibrary.dll │ │ │ └───native │ MyNativeLibrary.dll │ └───win8-x86 ├───lib │ └───net40 │ MyLibrary.dll │ └───native MyNativeLibrary.dll
Given the above package the following things happen:
When not on Windows 8 the
lib/net40/MyLibrary.dllassembly is used.
When on Windows 8 the
runtimes/win8-<architecture>/lib/MyLibrary.dllis used and the
native/MyNativeHelper.dllis copied to the output of your build.
In the example above the
lib/net40 assembly is purely managed code, whilst the assemblies in the runtimes folder will p/invoke into the native helper assembly to call APIs specific to Windows 8.
Only a single
lib folder is ever be picked, so if there is a runtime specific folder it's chosen over non-runtime specific
lib. The native folder is additive, if it exists it's copied to the output of the build.
Another way to use runtimes is to ship a package that is purely a managed wrapper over a native assembly. In this scenario you create a package like the following:
└───MyLibrary └───runtimes ├───win8-x64 │ ├───lib │ │ └───net451 │ │ MyLibrary.dll │ │ │ └───native │ MyImplementation.dll │ └───win8-x86 ├───lib │ └───net451 │ MyLibrary.dll │ └───native MyImplementation.dll
In this case there is no top-level
lib folder as that folder as there is no implementation of this package that doesn't rely on the corresponding native assembly. If the managed assembly,
MyLibrary.dll, was exactly the same in both of these cases then we could put it in a top level
lib folder, but because the lack of a native assembly doesn't cause the package to fail installing if it was installed on a platform that wasn't win-x86 or win-x64 then the top level lib would be used but no native assembly would be copied.
Authoring packages for NuGet 2 and NuGet 3
If you want to create a package that can be consumed by projects using
packages.config as well as packages using
project.json then the following apply:
Ref and runtimes only work on NuGet 3. They are both ignored by NuGet 2.
You cannot rely on
uninstall.ps1to function. These files execute when using
packages.config, but are ignored with
project.json. So your package needs to be usable without them running.
init.ps1still runs on NuGet 3.
Targets and Props installation is different, so make sure that your package works as expected on both clients.
Subdirectories of lib must be a TxM in NuGet 3. You cannot place libraries at the root of the
Content is not copied automatically with NuGet 3. Consumers of your package could copy the files themselves or use a tool like a task runner to automate copying the files.
Source and config file transforms are not run by NuGet 3.
If you are supporting NuGet 2 and 3 then your
minClientVersion should be the lowest version of NuGet 2 client that your package works on. In the case of an existing package it shouldn't need to change.