Special Windows 10 issue 2015
Volume 30 Number 11
Visual Studio Tooling - NuGet Features Enhance Windows 10 Development
By Jeff Fritz | Windows 2015
Several new tools are now available from the NuGet team. It worked with several teams at Microsoft to deliver a new version of the NuGet client to support the Universal Windows Platform (UWP) and the new Portable Class Libraries (PCLs). The new NuGet tools are available through Tools | Extensions and Updates | Update in Visual Studio 2015, as well as the NuGet distribution site at bit.ly/1MgNt2J. NuGet has also released a new version of the NuGet command-line tool you can download from the same location on dist.nuget.org. This article will review the new capabilities and the process Windows developers need to follow to add NuGet support to their Windows 10 projects.
Beginning with ASP.NET 5, NuGet introduced support for the project.json file to describe project dependencies with a clear definition of the packages upon which you would immediately depend. In ASP.NET 5, this is the only file that defines project configuration. With NuGet 3.1, though, you use this file in your Universal Windows projects and modern PCLs (that target DNX, UWP and the Microsoft .NET Framework 4.6) to define your package references. The good news about this is the “Manage Packages” dialog in Visual Studio will appropriately maintain your packages.config or project.json file for you based on the type of project you’re developing.
This shift from the packages.config model also lets you “reboot” references in your projects and use the new transitive dependency capabilities of NuGet. Developers and package authors reported to the NuGet team that when they add packages to projects, their packages.config file became polluted with dependencies from their dependent packages.
For example, NHibernate is a package that depends on the Iesi.Collections package. In packages.config, there are two references, NHibernate and Iesi.Collections. When it’s time to update NHibernate, there’s the question, “Do I also update Iesi.Collections?” The opposite problem also exists. If there’s an update for Iesi.Collections, do I need to update NHibernate to support the new features in Iesi.Collections? Developers could end up in this ugly cycle of managing their project’s package dependencies brought to them through package references.
The transitive dependencies feature of NuGet abstracts this decision to update package references with improved support for semantic versioning in package definition files (nuspec documents). Developers have specified a range of dependency versions their packages support. When NuGet installs clients, those dependencies add a hard reference to a specific version in the packages.config file and those referenced packages look like any other package reference you’ve added to your project. You can see a great example of this problem in Figure 1.
Figure 1 The Contents of an ASP.NET MVC packages.config File
<?xml version="1.0" encoding="utf-8"?> <packages> <package id="Antlr" version="188.8.131.5204" targetFramework="net46" /> <package id="bootstrap" version="3.0.0" targetFramework="net46" /> <package id="EntityFramework" version="6.1.3" targetFramework="net46" /> <package id="jQuery" version="1.10.2" targetFramework="net46" /> <package id="jQuery.Validation" version="1.11.1" targetFramework="net46" /> <package id="KendoUICore" version="2015.2.624" targetFramework="net46" /> <package id="Microsoft.AspNet.Identity.Core" version="2.2.1" targetFramework="net46" /> <package id="Microsoft.AspNet.Identity.EntityFramework" version="2.2.1" targetFramework="net46" /> <package id="Microsoft.AspNet.Identity.Owin" version="2.2.1" targetFramework="net46" /> <package id="Microsoft.AspNet.Mvc" version="5.2.3" targetFramework="net46" /> <package id="Microsoft.AspNet.Razor" version="3.2.3" targetFramework="net46" /> <package id="Microsoft.AspNet.Web.Optimization" version="1.1.3" targetFramework="net46" /> <package id="Microsoft.AspNet.WebPages" version="3.2.3" targetFramework="net46" /> <package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="1.0.0" targetFramework="net46" /> <package id="Microsoft.jQuery.Unobtrusive.Validation" version="3.2.3" targetFramework="net46" /> <package id="Microsoft.Net.Compilers" version="1.0.0" targetFramework="net46" developmentDependency="true" /> <package id="Microsoft.Owin" version="3.0.1" targetFramework="net46" /> <package id="Microsoft.Owin.Host.SystemWeb" version="3.0.1" targetFramework="net46" /> <package id="Microsoft.Owin.Security" version="3.0.1" targetFramework="net46" /> <package id="Microsoft.Owin.Security.Cookies" version="3.0.1" targetFramework="net46" /> <package id="Microsoft.Owin.Security.Facebook" version="3.0.1" targetFramework="net46" /> <package id="Microsoft.Owin.Security.Google" version="3.0.1" targetFramework="net46" /> <package id="Microsoft.Owin.Security.MicrosoftAccount" version="3.0.1" targetFramework="net46" /> <package id="Microsoft.Owin.Security.OAuth" version="3.0.1" targetFramework="net46" /> <package id="Microsoft.Owin.Security.Twitter" version="3.0.1" targetFramework="net46" /> <package id="Microsoft.Web.Infrastructure" version="184.108.40.206" targetFramework="net46" /> <package id="Modernizr" version="2.6.2" targetFramework="net46" /> <package id="Newtonsoft.Json" version="6.0.4" targetFramework="net46" /> <package id="Owin" version="1.0" targetFramework="net46" /> <package id="Respond" version="1.2.0" targetFramework="net46" /> <package id="WebGrease" version="1.5.2" targetFramework="net46" /> </packages>
When I add these things to my project, I really just need Microsoft.AspNet.Mvc, Microsoft.AspNet.Identity.EntityFramework, Newtonsoft.Json and Microsoft.Owin.Security.MicrosoftAccount. The other items referenced by these four packages are just noise, and now I have hard references to specific versions. With the transitive dependencies feature, the versions of these other packages go away. I’m left managing just the four libraries I’ll actually use in my project.
The NuGet client will resolve and manage these other packages behind the scenes for you, and keep those references within the constraints of the dependent versions declared by the packages you’re using in your project. This should dramatically simplify the project references experience.
Common Local Package Cache
Developers often have a “tribe” of packages and tools they prefer. Why download and install them multiple times on a single workstation when you clearly already have them in one project and want to use them in another? With projects managed by project.json, NuGet downloads and stores a copy of the packages in a global packages folder located in your %userprofile%\.nuget\packages folder. This should reduce disk space used on your workstation. It also prevents extra calls to fetch packages from NuGet.org to get items you already have.
Project.json and common local package cache support is available for ASP.NET 5 with NuGet 3.0, and for other project types starting with NuGet 3.1.
Starting with NuGet 3.1 when using project.json, you deprecate support for executing the install.ps1/uninstall.ps1 scripts and delivering elements in the /content package folder. Installing packages with these elements will neither execute the install.ps1 file nor copy content to your project. However, in projects that still use packages.config files, the current behavior is still supported. There are several reasons for this:
- With transitive package restore, picking what to uninstall and install is impossible to do reliably.
- When copying content into the user project, and packages are updated, there’s an implicit uninstall process that you can’t reliably run.
- NuGet needs to fully support development outside Visual Studio. With the movement to support a full cross-platform .NET development experience, Windows Powershell isn’t available in other environments. More developers are also working outside of Visual Studio on .NET code, and they need support.
- Other package managers deliver a great experience for managing and delivering content. NuGet works well as a package manager for the .NET Framework, so continuing to use it is encouraged.
- There’s no longer support for the “any” framework. You can no longer place files directly on the root of the build and lib folders and have them delivered to a project. It’s important you declare which frameworks your files support so NuGet knows the priority order to resolve those references.
- Solution packages are no longer supported. These packages aren’t modifying any specific project’s capabilities and were typically used to deliver shared resources that were reused across projects. With the new shared packages folder, these resources may already be on disk from another project.
New Target Frameworks
Another aspect of this new version of NuGet is support for new development frameworks and improved native package support across OSes and architectures. NuGet is reaching further outside the managed .NET Framework model to support more ecosystems and empower you to take libraries to previously unreachable environments.
Target framework monikers (TFM) is shorthand used to create a package to declare which frameworks binaries support and which dependencies each framework needs. You’ll find folder names in the package’s lib and ref folders that use this notation. There are also elements in the package’s nuspec dependencies element that declare a target Framework attribute with one of the TFM values to direct the NuGet client to deliver an appropriate library to a consuming project.
The following TFMs are still available and the new TFMs being introduced are listed in Figure 2.
Figure 2 Target Frameworks Supported with NuGet 3.x
|Description||Base Code||Available Versions|
|Managed Framework Applications (Windows Forms, Console Applications, Windows Presentation Foundation, ASP.NET)||net||net11, net20, net35, net35-client, net35-full, net4, net40, net40-client, net40-full, net403, net45, net451, net452, net46|
|Windows Store||netcore||win8 = netcore45, win81 = netcore451, uap10.0|
|Windows Phone (appx model)||wpa||wpa81|
|Windows Phone (Silverlight)||wp||wp7 = sl3-wp, wp71 = sl4-wp71, sl4-wp, wp8 = wp8-, wp81|
|Silverlight||sl||sl2, sl3 = sl30, sl4 = sl40, sl5 = sl50|
|Xamarin||mono, MonoMac, Xamarin.Mac, MonoAndroid10, MonoTouch10, Xamarin.iOS10|
|Compact Framework||net-cf||net20-cf, net35-cf = cf35, net40-cf|
|Micro Framework||netmf||netmf41, netmf42, netmf43|
Those items listed with an equals (=) symbol are synonyms supported by NuGet. That’s a lot of support for a lot of different frameworks, but it can be confusing. Do you need to provide support for micro-framework in your managed framework package? How much Silverlight support do you need? You need to answer these questions to best fit the needs of your consumers.
You’ll notice there’s no explicit call to support PCLs in the table. While NuGet supports those combinations of frameworks, it wants you to have a more forward-compatible moniker for modern PCLs. This will give you greater flexibility in constructing your packages and defining the frameworks you support. NuGet 3.1 introduces the dotnet target moniker for modern PCLs.
Dotnet Target Moniker
In previous versions of NuGet, you could specify the frameworks with a PCL that worked as a collection of TFM abbreviations joined with plus symbols. You could end up with folder names like “portable-net45+win8+wpa81+wp8.” That could be confusing and lead to incompatibility issues for your consumers. To make the PCL and cross-platform development experience easier, NuGet introduced the dotnet moniker.
This moniker isn’t tied directly to any specific version or framework capabilities. It’s an indirect reference that tells NuGet, “This is the reference you should use if it supports the framework and runtime capabilities that you have.” The NuGet client then investigates that reference to determine the features and frameworks it supports. This process continues until the NuGet client resolves the exact features supported by the dotnet reference. It will then apply it if and only if it matches the features and requirements of your project. You can reference the dotnet moniker with the .NET Framework 4.5 and later derived framework versions, including Xamarin Android and Xamarin iOS.
This doesn’t mean you can simply build a PCL, bundle it with declared dotnet dependencies and be done. If you want to be able to support projects using older versions of Visual Studio and NuGet clients building with traditional portable class libraries, you should still create and place a reference to the full PCL target framework moniker.
When installing a package into a project type that’s fully compatible with the dotnet moniker (.NET Framework 4.6, UWP or ASP.NET 5), the dotnet moniker will be sought last. That will happen after attempting to find a reference that matches the framework or less-specific framework of your project. This hierarchy looks like Figure 3.
Figure 3 Hierarchy of Frameworks Inspected for References for a Universal Windows Platform Project
If your project is a modern PCL using project.json that targets any of these frameworks and no other, the dotnet moniker will be analyzed first. That will be followed by the standard PCL resolution strategy, as shown in Figure 4.
Figure 4 Hierarchy of Frameworks Inspected for References in a Modern Portable Class Library Project
NuGet Command Line
The command-like executable for NuGet, nuget.exe, is now available with support to install, update, and restore packages to a project with either a packages.config or project.json file. The pack command continues to work with nuspec files on disk and packages.config files. It hasn’t been updated to generate a nuspec file based on a project.json file. To work around this, you’ll need to craft your own nuspec file for any new package content you construct with a project.json packages reference. A future release will include an update to address this.
This version of the command-line executable also supports NuGet.org v3 endpoints. This new version of the nuget.org feed provides faster interactions and is a more reliable service. There’s built-in redundancy and a content-delivery network enabled to assist in quickly delivering packages. Download a copy of the updated NuGet.exe at bit.ly/1UV0kcU.
If you’ve installed Windows 10 SDK/Windows 10 tools after upgrading the NuGet extension, the installer will downgrade the extension back to Version 3.1. You’ll need to update it again to at least 3.1.1. The version showing up in the Extensions and Updates dialog is 3.1.60724.766. The Windows PowerShell console is 220.127.116.11.
These features that support the Windows 10 UWP application development and PCL projects are now available. These changes are the first step in broader use of the package manager and the .NET Framework. Microsoft continues to improve the .NET development experience, and will focus on delivering a package manager to support all .NET developers on any platform building any type of project.
Jeffrey T. Fritz is a senior program manager at Microsoft working on the NuGet team. He enjoys long walks on the beach and killer Web applications that scale in the cloud. Reach him at email@example.com.
Thanks to the following technical experts for reviewing this article: Members of the NuGet team at Microsoft