【问题标题】:How to create a project template that installs latest NuGet dependencies如何创建安装最新 NuGet 依赖项的项目模板
【发布时间】:2017-07-28 13:18:52
【问题描述】:

我想创建一个模板来安装最新版本的 NuGet 包及其所有依赖项。使用NuGet.VisualStudio.TemplateWizard 的最常见解决方案仅安装指定的包版本,不解决任何依赖关系。基本上我想在创建使用我的模板的项目时运行Install-Package example

【问题讨论】:

    标签: c# .net visual-studio nuget


    【解决方案1】:

    如何创建安装最新 NuGet 依赖项的项目模板?

    显然,您的要求非常明确。但我们不建议您这样做。因为更新包会破坏模板。

    我们所知道的是,预安装的软件包使用 template wizards。当模板被实例化时,会调用一个特殊的向导。该向导会加载需要安装的包列表并将该信息传递给相应的 NuGet API。

    此外,向导中需要idversion 属性,用于指定软件包的版本,即使有更新的版本可用。 这可以防止包更新破坏模板,将更新包的选择权留给使用模板的开发人员。

    更重要的是,开发者更新包是一件非常简单的事情。开发者可以根据自己的需求更新部分包,不需要全部更新。

    【讨论】:

    • 你如何想象在一个空项目中包含最新的 jQuery 来破坏一个模板?如果奇迹发生,更新一次模板比为每个新版本和模板实例更新 jQuery 更容易。我认为模板开发人员应该决定他是否想要最新版本,这取决于模板。顺便说一句,新的 .csproj 文件通过PackageReference 以非常灵活的方式允许这样做,但目前它太有问题了。
    【解决方案2】:

    找到了 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 方法都是内部的(不可用)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-06-21
      • 2011-07-21
      • 1970-01-01
      • 1970-01-01
      • 2019-03-19
      • 1970-01-01
      • 1970-01-01
      • 2015-10-14
      相关资源
      最近更新 更多