Project Templates and preinstalled NuGet packages

10/22 Update: This post was written before this feature became a part of NuGet.
This feature is now a part of NuGet and the latest version of this information can be found on the NuGet docs site.
There is also a sample project available.

Over the last few years the ASP.NET team has been including more and more libraries into the various project templates that we ship with Visual Studio and other products. The latest MVC 3 templates come with jQuery, jQuery UI, jQuery Validation, Modernizr, and Entity Framework. All this built-in functionality is great but one remaining snag is that upgrading all the packages by hand can be a pain. Of course the NuGet package manager is an excellent tool that solves the package upgrade problem but so far having project templates with preinstalled NuGet packages was not possible.

This post describes a new feature that will be shipping in NuGet 1.5: preinstalled NuGet packages. Since it is not documented anywhere at this time the purpose of this post is to describe how to create a VS project template with NuGet packages. If you play around with it please also provide feedback so we can make changes/improvements.

Authoring VS project templates is out of scope of this article but you can read more on how to create a project template directly using Visual Studio or using the Visual Studio SDK.

Adding packages to a project templates

NuGet 1.5 is not out yet but the feature has already been checked in and you can try it out by grabbing a recent NuGet preview build and installing the Visual Studio add-in (note that you might have to remove the previous version via the Extension Manager first).

Preinstalled packages work using project template wizards. A special wizard gets invoked when the project gets instantiated. The wizard loads the list of packages that need to be installed and passes that information to the appropriate NuGet APIs. The project template needs to specify where to find the package nupkg files. Currently two package repositories are supported:

  1. Packages embedded inside of a VSIX package.
  2. Packages embedded inside of the project template itself.

A frequent question is why not support downloading the nupkg files directly from https://nuget.org. We decided not to support such an option because users expect project templates to instantiate quickly and downloading files from the internet would slow things down. Also, it would not work on a plane or in other situations where a connection is not available.

To add preinstalled packages to your project template you need to:

  1. Edit your vstemplate file and add a reference to the NuGet template wizard by adding a WizardExtension element:

     <WizardExtension>
        <Assembly>NuGet.VisualStudio.Interop, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null</Assembly>
        <FullClassName>NuGet.VisualStudio.TemplateWizard</FullClassName>
    </WizardExtension>
    

    NuGet.VisualStudio.Interop.dll is a new assembly that only contains the TemplateWizard class. This class is a simple wrapper that calls into the actual implementation that lives in NuGet.VisualStudio.dll. The assembly version will never change so that project templates continue to work with new versions of NuGet.

  2. Add the list of packages to install in the project:

     <WizardData>
        <packages>
            <package id="jQuery" version="1.4.4" />
        </packages>
    </WizardData>
    

    You can of course add multiple <package> elements. Both the id and version attributes are required. You will notice that this means that a specific version of a package will be installed, even if a newer version is available in the online package feed. We cannot just update to the latest version because a future version of a package might introduce incompatibilities that would break an older version of the project template. It is up to the developer to upgrade using the package manager.

The remaining step is to specify the repository where NuGet can find the package files. As mentioned earlier, two package repository modes are supported:

VSIX package repository

The approach I recommend for deploying Visual Studio project templates is through a VSIX package (read more about VSIX deployment here). The VSIX method is preferable because it allows you to package multiple project templates together and allows developers to easily discover your templates using the VS Extension Manager or the Visual Studio Gallery. On top of that you can easily push updates to your users using the Extension Manager automatic update mechanism.

  1. To specify a VSIX as a package repository you modify the <package>element:

     <packages repository="extension"
              repositoryId="MyTemplateExtension.46431780-a0c7-44e0-83c7-5dbd985f8e49">
        ...
    </packages>
    

The repository attribute specifies the type of repository (“extension”) while repositoryId is the unique identifier of your VSIX (i.e. the value of the ID attribute in the extension’s vsixmanifest file).

You need to add your nupkg files as custom extension content and ensure that they are located under a folder called Packages within the VSIX package. You can place the nupkg files in the same VSIX as your project templates or you can have the packages be located in a separate VSIX if that makes more sense for your scenario (just note that you should not reference VSIXs you do not have control over since they could change in the future and your project templates would break).

Template package repository

If packaging multiple projects is not important to you (e.g. you’re only distributing a single project template), a simpler but also more limited approach is to include the nupgk files in the project template zip file itself.

However, if you are bundling a set of project templates that relate to each other and share NuGet packages (e.g. you are shipping a custom MVC project template with versions for Razor, Web Forms, C#, and VB.NET), we do not recommend adding the NuGet packages directly to each project template zip file. It needlessly increases the size of the project template bundle.

  1. To specify the project template as a package repository you modify the <package>element:

     <packages repository="template">
        ...
    </packages>
    

The repository attribute now has the value “template” and the repositoryId attribute is not longer required. The nupkg files need to be placed into the root directory of the project template.