Poma
Poma

Reputation: 8484

How to create a project template that installs latest NuGet dependencies

I want to create a template that installs the latest version of a NuGet package and all of its dependencies. Most common solution using NuGet.VisualStudio.TemplateWizard installs only specified package version and doesn't resolve any dependencies. Basically I want to run Install-Package example when a project using my template is created.

Upvotes: 2

Views: 1152

Answers (2)

Poma
Poma

Reputation: 8484

Found 2 ways to do that. New .csproj standard supports PackageReference directives for including NuGet packages and supports version wildcards and prefers highest version available. But it is currently too buggy so I ended up implementing my own IWizard that works like NuGet's default wizard but installs latest packages and dependencies:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using EnvDTE;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.TemplateWizard;
using NuGet.VisualStudio;
using Task = System.Threading.Tasks.Task;

namespace Example
{
    public class NuGetTemplateWizard : IWizard
    {
        List<string> _packages;

        public void RunStarted(object automationObject, Dictionary<string, string> replacementsDictionary, WizardRunKind runKind, object[] customParams)
        {
            if (customParams.Length > 0) {
                var vstemplate = XDocument.Load((string)customParams[0]);
                _packages = vstemplate.Root
                    .ElementsNoNamespace("WizardData")
                    .ElementsNoNamespace("packages")
                    .ElementsNoNamespace("package")
                    .Select(pkg => pkg.Attribute("id").Value)
                    .ToList();
            }
        }

        public void ProjectFinishedGenerating(Project project)
        {
            Task.Run(delegate {
                var componentModel = (IComponentModel)Package.GetGlobalService(typeof(SComponentModel));
                var _installer = componentModel.GetService<IVsPackageInstaller2>();

                foreach (var package in _packages) {
                    _installer.InstallLatestPackage(null, project, package, false, false);
                }
            });
        }

        public bool ShouldAddProjectItem(string filePath) { return true; }
        public void BeforeOpeningFile(ProjectItem projectItem) { }
        public void ProjectItemFinishedGenerating(ProjectItem projectItem) { }
        public void RunFinished() { }
    }
}

and in .vstemplate:

  <WizardExtension>
    <Assembly>Example, Version=1.0.0.0, Culture=neutral, PublicKeyToken=7a55be3860fb01d1</Assembly>
    <FullClassName>Example.NuGetTemplateWizard</FullClassName>
  </WizardExtension>
  <WizardData>
    <packages>
      <package id="Newtonsoft.Json" />
    </packages>
  </WizardData>

Also I'm not sure whether it is safe to install packages in background via Task.Run but it feels more responsive this way and all async nuget methods are internal (not available) anyway.

Upvotes: 0

Leo Liu
Leo Liu

Reputation: 76910

How to create a project template that installs latest NuGet dependencies?

Obviously, your requirement is very clear. But we do not recommend you doing that. Because update the packages will break the template.

What we know is that preinstalled packages work using template wizards. A special wizard gets invoked when the template gets instantiated. The wizard loads the list of packages that need to be installed and passes that information to the appropriate NuGet APIs.

Besides, both the id and version attributes are required in the wizard, which used to specify version of a package will be installed even if a newer version is available. This prevents package updates from breaking the template, leaving the choice to update the package to the developer using the template.

what's more, update the package by the developer is a very simple matter. And developers could update some packages according to their requirement, no need update all packages.

Upvotes: 2

Related Questions