How to programmatically install a NuGet package?

前端 未结 2 1058
礼貌的吻别
礼貌的吻别 2020-12-30 16:12

I want to programmatically install a NuGet package to a project, and update the .csproj file, and the packages.config file.

I am using the

相关标签:
2条回答
  • 2020-12-30 16:47

    Thanks to @MattWard and @bashis, i've written my own code generator:

    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 hard coded the value: MSIL

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

    This work fine for me.

    0 讨论(0)
  • 2020-12-30 16:51

    (Assuming you are writing the code generator on your own)

    I am not sure this is the best solution but you could try something like this:

    var assembly = Assembly.LoadFile("path_to_dll");
    string info = assembly.FullName; // contains something like "AssemblyName, Version=0.0.0.0, Culture=neutral, PublicKeyToken=foobar"
    

    which will add some overhead by loading the assembly, but will presumably do the job.

    0 讨论(0)
提交回复
热议问题