【问题标题】:How to download latest nuget package programmatically in .NET Core?如何在 .NET Core 中以编程方式下载最新的 nuget 包?
【发布时间】:2019-04-04 06:54:10
【问题描述】:

需要在 .Net Core 应用中拉取并安装最新版本的 nugets

Nuget.Core 是可用的。但是在 .Net Standard 的情况下是可用的。

希望使用 Nuget.Client 进行更新。 How to download a nupkg package from nuget programmatically in .NET Core? 这几乎是相同的模式,但我找不到该问题的相关答案。

.Net标准实现 How to get nuget package version programmatically from a nuget feed?

也遇到过 https://social.msdn.microsoft.com/Forums/en-US/f10a9c7e-4ad9-4fc5-be94-adfc2eb42a1a/install-a-nuget-package-programmatically?forum=vsx

当我运行一组测试并且我的 nuggets 需要使用最新版本更新时,可能会发生这种情况。这样我的测试将针对最新的 nuget 版本进行验证

【问题讨论】:

  • 这感觉是个坏主意。使用特定版本的软件包可能是有原因的。如果您的测试覆盖了 100% 的使用 any 依赖项的代码,那么我能想到的唯一警告是,以便掩盖次要版本中的任何细微更改。我还建议不要更改主要版本,因为这可能会导致根本无法编译代码。
  • 正如我作为对下面答案的评论所写的那样,NuGet.Core 是一个可以追溯到 NuGet 2.x 的古老包,它可能来自 VS2012 或 VS2013 时代。 NuGet 的当前版本是 5.0.0。甚至 Nate McMaster 在您链接的问题中的回答也表示不再维护 NuGet.Core。我还不太了解 NuGet 包,所以我只能建议在 NuGet.Client repo 中搜索您要使用的类名,然后查看它所在的项目以了解要引用哪个包。
  • 虽然我同意 phuzi 的评论。我们团队与之交谈的内部和企业客户非常重视安全性,他们从不在版本字符串中使用通配符,也不会自动更新。确定性构建至关重要,尤其是当您需要构建旧版本以进行回滚时。这些团队发现手动升级依赖项的努力值得其他好处。

标签: c# .net-core nuget


【解决方案1】:

所以,要正确地将引用添加到给定的.csproj,这就是我要做的:

var CsprojDoc = new XmlDocument();
CsprojDoc.LoadXml("*your_csproj_content*");
var Nsmgr = new XmlNamespaceManager(CsprojDoc.NameTable);
Nsmgr.AddNamespace("x", "http://schemas.microsoft.com/developer/msbuild/2003");

IPackage packageInfos = GetNugetPackage(packageId, packageRepositoryUri);

XmlNode referenceNode = CsprojDoc.CreateNode(XmlNodeType.Element, "Reference", XmlNamespaceValue);
XmlAttribute includeAttribute = CsprojDoc.CreateAttribute("Include");

var targetFwProfile = CsprojDoc.SelectSingleNode("//x:TargetFrameworkProfile", Nsmgr);
string targetFrameworkProfile = string.Empty;
if (!string.IsNullOrEmpty(targetFwProfile?.InnerXml))
{
    targetFrameworkProfile = targetFwProfile.InnerXml;
}

var targetFwAttribute = GetTargetFrameworkFromCsproj();
Regex p = new Regex(@"\d+(\.\d+)+");
Match m = p.Match(targetFwAttribute.FrameworkName);
Version targetFwVersion = Version.Parse(m.Value);

// Get the package's assembly reference matching the target framework from the given '.csproj'.
var assemblyReference =
    packageInfos.AssemblyReferences
        .Where(a => a.TargetFramework.Identifier.Equals(targetFwAttribute.FrameworkName.Split(',').First()))
        .Where(a => a.TargetFramework.Profile.Equals(targetFrameworkProfile))
        .Last(a => (a.TargetFramework.Version.Major.Equals(targetFwVersion.Major) && a.TargetFramework.Version.Minor.Equals(targetFwVersion.Minor)) ||
        a.TargetFramework.Version.Major.Equals(targetFwVersion.Major));

DownloadNugetPackage(packageInfos.Id, packageRepositoryUri, packagesFolderPath, packageInfos.Version.ToFullString());

string dllAbsolutePath = Path.GetFullPath($"{packagesFolderPath}\\{packageInfos.GetFullName().Replace(' ', '.')}\\{assemblyReference.Path}");
var assemblyInfos = Assembly.LoadFile(dllAbsolutePath);

includeAttribute.Value = $"{assemblyInfos.FullName}, processorArchitecture=MSIL";

referenceNode.Attributes.Append(includeAttribute);

XmlNode hintPathNode = CsprojDoc.CreateNode(XmlNodeType.Element, "HintPath", XmlNamespaceValue);
XmlNode privateNode = CsprojDoc.CreateNode(XmlNodeType.Element, "Private", XmlNamespaceValue);

hintPathNode.InnerXml = $"$(SolutionDir)\\packages\\{assemblyReference.Path}";
privateNode.InnerXml = "True";

referenceNode.AppendChild(hintPathNode);
referenceNode.AppendChild(privateNode);
var itemGroupNode = CsprojDoc.SelectSingleNode("//x:Project/x:ItemGroup/x:Reference", Nsmgr).ParentNode;
itemGroupNode.AppendChild(referenceNode);

这是我的DownloadNugetPackage 方法:

private static void DownloadNugetPackage(string packageId, Uri repoUri, string packagesFolderPath, string version)
{
    IPackageRepository packageRepository = PackageRepositoryFactory.Default.CreateRepository(repoUri.ToString());
    PackageManager packageManager = new PackageManager(packageRepository, packagesFolderPath);

    packageManager.InstallPackage(packageId, SemanticVersion.Parse(version));
}

我的GetTargetFrameworkFromCsproj

    public static TargetFrameworkAttribute GetTargetFrameworkFromCsproj()
    {
        XmlNode targetFrameworkNode = CsprojDoc.SelectSingleNode("//x:TargetFrameworkVersion", Nsmgr);
        return new TargetFrameworkAttribute($".NETFramework, Version={targetFrameworkNode.InnerXml}");
    }

还有我的GetNugetPackage 方法:

public static IPackage GetNugetPackage(string packageId, Uri repoUri, string version = null)
{
    IPackageRepository packageRepository = PackageRepositoryFactory.Default.CreateRepository(repoUri.ToString());
    IPackage package;

    if (!string.IsNullOrEmpty(version))
    {
        package = packageRepository.FindPackagesById(packageId).SingleOrDefault(p => p.Version.ToFullString().Equals(version));
    }
    else
    {
        package = packageRepository.FindPackagesById(packageId).SingleOrDefault(p => p.IsLatestVersion);
    }

    return package;
}

注意:这次我使用的是官方的 NuGet 包:Nuget.core 2.14:https://www.nuget.org/packages/NuGet.Core/

注意 2:当我添加一个新的 Reference 节点时,在 processorArchitecture 属性中,我已经硬编码了值:MSIL

如果你想测试它,你可以稍微调整一下。

这对我来说很好。

【讨论】:

  • 我正在研究 .Net Core 的相同实现。不幸的是,.Net Core 不支持 Nugget.Core,这是我的主要问题。
  • nuget.core 是 nuget 的一个古老版本。项目名称,因此包名称已更改,但很少从 nuget.org 删除旧包,以避免破坏依赖它们的任何人。如果您寻找packages starting with nuget.,任何具有 4.9 或更高版本的最新版本都支持 netstandard,并且是我们当前的版本(鉴于 VS2019 的发布,nuget 5.0.0 包将很快发布)
猜你喜欢
  • 1970-01-01
  • 2019-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-09
  • 2020-06-09
相关资源
最近更新 更多