2

Need to pull and install the latest version of nugets in .Net Core application

Nuget.Core was the available.however that was in the case of .Net Standard.

Looking to update using Nuget.Client. How to download a nupkg package from nuget programmatically in .NET Core? this is almost same pattern but i couldn't find relevant answers from that question.

.Net standard implementation How to get nuget package version programmatically from a nuget feed?

Also came across https://social.msdn.microsoft.com/Forums/en-US/f10a9c7e-4ad9-4fc5-be94-adfc2eb42a1a/install-a-nuget-package-programmatically?forum=vsx

Need to install latest version this can happen when am running a set of tests and my nuggets needs to updated with latest release.So that my tests will validated against latest nuget versions

joshcomley
  • 28,099
  • 24
  • 107
  • 147
Joe Pauly
  • 337
  • 3
  • 19
  • This feels like a bad idea. There can be reasons a particular version of a package is being used. The only caveat I can think of if your tests cover 100% of the code that uses _any_ dependency so that any subtle changes in minor releases are covered off. I'd also recommend against major version changes as that would likely result in not being able to compile the code at all. – phuzi Apr 04 '19 at 07:49
  • As I wrote as a comment to the answer below, NuGet.Core is an ancient package dating back to NuGet 2.x, which is probably from the VS2012 or VS2013 era. The current version of NuGet is 5.0.0. Even Nate McMaster's answer in a question you linked said that NuGet.Core is no longer maintained. I don't yet know the NuGet packages very well, so all I can suggest is searching the [NuGet.Client repo](https://github.com/NuGet/NuGet.Client) for the class name you want to use, then see what project it's in to know which package to reference. – zivkan Apr 04 '19 at 14:28
  • Although I agree with phuzi's comment. The internal and enterprise customers our team talks to that are serious about security, they never use wildcards in their version strings, or automatically update. Having deterministic builds is critical, particularly when you need to build an old version for a roll-back. These teams find the effort of manually upgrading dependencies to be worth the other benefits. – zivkan Apr 04 '19 at 14:32

1 Answers1

0

So, to add properly a reference into a given .csproj here's what I do:

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);

Here's my DownloadNugetPackage method:

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));
}

My GetTargetFrameworkFromCsproj

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

And my GetNugetPackage method:

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;
}

Note: This time, I'm using the official NuGet package: Nuget.core 2.14: https://www.nuget.org/packages/NuGet.Core/

Note 2: When I add a new Reference node, in the processorArchitecture attribute, I've hardcoded the value: MSIL

If you want to test it, you might tweak it a bit.

This worked fine for me.

Community
  • 1
  • 1
Akash Limbani
  • 1,283
  • 4
  • 14
  • 34
  • 2
    am looking at implementation of the same for .Net Core. unfortunately Nugget.Core is not supported in .Net Core which is my main issue. – Joe Pauly Apr 04 '19 at 09:18
  • 1
    nuget.core is an ancient version of nuget. project names, and therefore package names have changed, but old packages are rarely deleted from nuget.org to avoid breaking anyone who depends on them. If you look for [packages starting with nuget.](https://www.nuget.org/packages?q=nuget.), anything with a latest version of 4.9 or higher supports netstandard and is our current version (nuget 5.0.0 packages to be published very soon, given the release of VS2019) – zivkan Apr 04 '19 at 14:15