A quick description of how NuGet works today for UAP (csproj
+ project.json
) projects. Some documentation from NuGet is available.
I created a boring bog-standard console executable csproj, which produces these files:
c:\src\play\ConsoleApplication2>tree /f
Folder PATH listing for volume BOOTCAMP
Volume serial number is FC56-66FC
C:.
│ .gitattributes
│ .gitignore
│ ConsoleApplication2.sln
│
└───ConsoleApplication2
│ App.config
│ ConsoleApplication2.csproj
│ Program.cs
│
└───Properties
AssemblyInfo.cs
Then I added a project.json
file next to the csproj. It contains a package reference to a package that delivers build logic (GitVersioning) and one that just provides a build- and runtime reference (Dataflow):
{
"dependencies": {
"Nerdbank.GitVersioning": "1.4.41",
"Microsoft.Tpl.Dataflow": "4.5.24"
},
"frameworks": {
"net452": {}
},
"runtimes": {
"win": {}
}
}
By itself, this does nothing. If I build with MSBuild (without doing nuget restore
), the project doesn't use the additional logic that comes in the NuGet package. If my code actually used the Dataflow reference, the build would fail (because it wouldn't have the DLL to refer to).
But if I do restore, I get some interesting changes:
c:\src\play\ConsoleApplication2>nuget restore ConsoleApplication2.sln
MSBuild auto-detection: using msbuild version '14.0' from 'C:\Program Files (x86)\MSBuild\14.0\bin'.
Feeds used:
C:\Users\raines\AppData\Local\NuGet\Cache
C:\Users\raines\.nuget\packages\
https://api.nuget.org/v3/index.json
C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\
Restoring packages for c:\src\play\ConsoleApplication2\ConsoleApplication2\project.json...
All packages are compatible with .NETFramework,Version=v4.6.
Generating MSBuild file ConsoleApplication2.nuget.targets.
c:\src\play\ConsoleApplication2>tree /f
Folder PATH listing for volume BOOTCAMP
Volume serial number is FC56-66FC
C:.
│ .gitattributes
│ .gitignore
│ ConsoleApplication2.sln
│
└───ConsoleApplication2
│ App.config
│ ConsoleApplication2.csproj
│ ConsoleApplication2.nuget.targets
│ Program.cs
│ project.json
│ project.lock.json
│
└───Properties
AssemblyInfo.cs
Specifically, there's a project.lock.json
that contains information about the packages needed for the project (with conflicts resolved across the whole solution).
There's also ConsoleApplication2.nuget.targets
:
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(NuGetPackageRoot)' == ''">
<NuGetPackageRoot>$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
</PropertyGroup>
<ImportGroup>
<Import Project="$(NuGetPackageRoot)\Nerdbank.GitVersioning\1.4.41\build\dotnet\Nerdbank.GitVersioning.targets" Condition="Exists('$(NuGetPackageRoot)\Nerdbank.GitVersioning\1.4.41\build\dotnet\Nerdbank.GitVersioning.targets')" />
</ImportGroup>
</Project>
NuGet detected what packages contained build logic and included them in this generated file. This file is then included from C:\Program Files (x86)\MSBuild\Microsoft\NuGet\Microsoft.NuGet.targets
via
<Import Project="$(MSBuildProjectDirectory)\$(MSBuildProjectName).nuget.targets" Condition="Exists('$(MSBuildProjectDirectory)\$(MSBuildProjectName).nuget.targets') AND '$(IncludeNuGetImports)' != 'false'">
So now the build logic from the package is available to the project. To get the DLL references, at build time a target named ResolveNuGetPackageAssets
runs the ResolveNuGetPackageAssets
task, which loads project.lock.json
and emits assemblies into the @(Reference)
item. Then the usual reference-resolution machinery kicks in to get the right compiler command lines and so on.
Target "ResolveNuGetPackageAssets: (TargetId:20)" in file "C:\Program Files (x86)\MSBuild\Microsoft\NuGet\Microsoft.NuGet.targets" from project "c:\src\play\ConsoleApplication2\ConsoleApplication2\ConsoleApplication2.csproj" (target "ResolveAssemblyReferences" depends on it):
Task "MSBuild" skipped, due to false condition; ('%(_MSBuildProjectReferenceExistent.Extension)' == '.xproj') was evaluated as ('' == '.xproj').
Using "ResolveNuGetPackageAssets" task from assembly "C:\Program Files (x86)\MSBuild\Microsoft\NuGet\Microsoft.NuGet.Build.Tasks.dll".
Task "ResolveNuGetPackageAssets" (TaskId:10)
Task Parameter:IncludeFrameworkReferences=True (TaskId:10)
Task Parameter:RuntimeIdentifier=win (TaskId:10)
Task Parameter:ProjectLanguage=C# (TaskId:10)
Task Parameter:ProjectLockFile=project.lock.json (TaskId:10)
Task Parameter:
ContentPreprocessorValues=
rootnamespace
Value=ConsoleApplication2
assemblyname
Value=ConsoleApplication2
fullpath
Value=c:\src\play\ConsoleApplication2\ConsoleApplication2
outputfilename
Value=ConsoleApplication2.exe
filename
Value=ConsoleApplication2.csproj (TaskId:10)
Task Parameter:ContentPreprocessorOutputDirectory=obj\Debug\\NuGet (TaskId:10)
Task Parameter:TargetMonikers=.NETFramework,Version=v4.5.2 (TaskId:10)
Output Item(s):
ReferenceCopyLocalPaths=
C:\Users\raines\.nuget\packages\Microsoft.Tpl.Dataflow\4.5.24\lib\portable-net45+win8+wpa81\System.Threading.Tasks.Dataflow.dll
NuGetIsFrameworkReference=false
NuGetPackageId=Microsoft.Tpl.Dataflow
NuGetPackageVersion=4.5.24
NuGetSourceType=Package
Private=false (TaskId:10)
Output Item(s):
_ReferencesFromNuGetPackages=
C:\Users\raines\.nuget\packages\Microsoft.Tpl.Dataflow\4.5.24\lib\portable-net45+win8+wpa81\System.Threading.Tasks.Dataflow.dll
NuGetIsFrameworkReference=false
NuGetPackageId=Microsoft.Tpl.Dataflow
NuGetPackageVersion=4.5.24
NuGetSourceType=Package
Private=false (TaskId:10)
Output Item(s):
ReferencedNuGetPackages=
Microsoft.Tpl.Dataflow
Nerdbank.GitVersioning (TaskId:10)
Done executing task "ResolveNuGetPackageAssets". (TaskId:10)
Added Item(s):
Reference=
C:\Users\raines\.nuget\packages\Microsoft.Tpl.Dataflow\4.5.24\lib\portable-net45+win8+wpa81\System.Threading.Tasks.Dataflow.dll
NuGetIsFrameworkReference=false
NuGetPackageId=Microsoft.Tpl.Dataflow
NuGetPackageVersion=4.5.24
NuGetSourceType=Package
Private=false
Set Property: DTARUseReferencesFromProject=true
Task "CreateItem" skipped, due to false condition; ('@(_NuGetContentItems)' != '') was evaluated as ('' != '').
Done building target "ResolveNuGetPackageAssets" in project "ConsoleApplication2.csproj".: (TargetId:20)