【发布时间】:2017-07-28 13:18:52
【问题描述】:
我想创建一个模板来安装最新版本的 NuGet 包及其所有依赖项。使用NuGet.VisualStudio.TemplateWizard 的最常见解决方案仅安装指定的包版本,不解决任何依赖关系。基本上我想在创建使用我的模板的项目时运行Install-Package example。
【问题讨论】:
标签: c# .net visual-studio nuget
我想创建一个模板来安装最新版本的 NuGet 包及其所有依赖项。使用NuGet.VisualStudio.TemplateWizard 的最常见解决方案仅安装指定的包版本,不解决任何依赖关系。基本上我想在创建使用我的模板的项目时运行Install-Package example。
【问题讨论】:
标签: c# .net visual-studio nuget
如何创建安装最新 NuGet 依赖项的项目模板?
显然,您的要求非常明确。但我们不建议您这样做。因为更新包会破坏模板。
我们所知道的是,预安装的软件包使用 template wizards。当模板被实例化时,会调用一个特殊的向导。该向导会加载需要安装的包列表并将该信息传递给相应的 NuGet API。
此外,向导中需要id 和version 属性,用于指定软件包的版本,即使有更新的版本可用。 这可以防止包更新破坏模板,将更新包的选择权留给使用模板的开发人员。
更重要的是,开发者更新包是一件非常简单的事情。开发者可以根据自己的需求更新部分包,不需要全部更新。
【讨论】:
PackageReference 以非常灵活的方式允许这样做,但目前它太有问题了。
找到了 2 种方法来做到这一点。新的 .csproj 标准支持包含 NuGet 包的 PackageReference 指令,并支持版本通配符,并首选可用的最高版本。但它目前的问题太大,所以我最终实现了自己的 IWizard,它的工作方式类似于 NuGet 的默认向导,但安装了最新的包和依赖项:
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() { }
}
}
在 .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>
此外,我不确定通过Task.Run 在后台安装软件包是否安全,但这种方式感觉更灵敏,而且所有异步 nuget 方法都是内部的(不可用)。
【讨论】: