如何以编程方式安装 NuGet 包? [英] How to programmatically install a NuGet package?

查看:18
本文介绍了如何以编程方式安装 NuGet 包?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想以编程方式将 NuGet 包安装到项目中,并更新 .csproj 文件和 packages.config 文件.

我正在使用官方的 Nuget.core 框架,其源代码可在此处获得:https://github.com/NuGet/NuGet2

我没有使用 NuGet 包:https://www.nuget.org/packages/NuGet.Core/但是在GitHub上找到的源代码可以做一些调试.

<块引用>

注意:我使用的是 2.11 版本,而不是 2.13

我能够在所需目录下载包并更新 packages.config 文件:

//---- 在所需路径下载并安装包 ----字符串 packageID = "Newtonsoft.json";var sourceUri = new Uri("https://packages.nuget.org/api/v2");//返回一个 IPackagevar package = GetNugetPackage(packageID, sourceUri);IPackageRepository sourceRepository = PackageRepositoryFactory.Default.CreateRepository(sourceUri.ToString());string packagesPath = "../../TestFiles/packages";PackageManager packageManager = new PackageManager(sourceRepository, packagesPath);packageManager.InstallPackage(packageID, SemanticVersion.Parse(package.Version.ToFullString()));//---- 更新packages.config"文件 ----var packageReferenceFile = new PackageReferenceFile("../../TestFiles/packages.config");//获取要添加的当前项目的目标框架 -->package.config 文件中的 targetframework="net452" 属性var currentTargetFw = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(TargetFrameworkAttribute), false);var targetFrameworkAttribute = ((TargetFrameworkAttribute[])currentTargetFw).FirstOrDefault();//更新 packages.config 文件packageReferenceFile.AddEntry(package.GetFullName(), SemanticVersion.Parse(package.Version.ToFullString()), false, new FrameworkName(targetFrameworkAttribute.FrameworkName));

现在我需要更新 .csproj,这是棘手的部分...

到目前为止,这是我尝试过的:

string csprojFilePath = "../../TestFiles/test.csproj";var project = new MSBuildProjectSystem(csprojFilePath);字符串 pathToAnExistingNugetPackageDll = "../../TestFiles/packages/Newtonsoft.json/lib/net45/Newtonsoft.json.dll"project.AddReference(pathToAnExistingNugetPackageDll, Stream.Null);项目.保存();

这段代码更新了 .csproj 文件,它添加了一个新的 reference 节点,如下所示:

<Reference Include="Newtonsoft.json"><HintPath>..packagesNewtonsoft.jsonlib
et45Newtonsoft.json.dll</HintPath></参考>

但我需要一个 complete reference 节点,如下所示:

<Reference Include="Newtonsoft.json, Version=9.0.8, Culture=neutral, PublicKeyToken=b03f4f7d11d50a3a, processorArchitecture=MSIL"><HintPath>..packagesNewtonsoft.jsonlib
et45Newtonsoft.json.dll</HintPath><私人>真实</私人></参考>

我该怎么做?

解决方案

感谢 @MattWard@bashis,我编写了自己的代码生成器:p>

所以,要正确地将引用添加到给定的 .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);字符串 targetFrameworkProfile = string.Empty;if (!string.IsNullOrEmpty(targetFwProfile?.InnerXml)){targetFrameworkProfile = targetFwProfile.InnerXml;}var targetFwAttribute = GetTargetFrameworkFromCsproj();正则表达式 p = 新正则表达式(@"d+(.d+)+");匹配 m = p.Match(targetFwAttribute.FrameworkName);版本 targetFwVersion = Version.Parse(m.Value);//从给定的.csproj"中获取与目标框架匹配的包的程序集引用.var 组件参考 =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());字符串 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 = 真";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包;if (!string.IsNullOrEmpty(version)){package = packageRepository.FindPackagesById(packageId).SingleOrDefault(p => p.Version.ToFullString().Equals(version));}别的{包 = packageRepository.FindPackagesById(packageId).SingleOrDefault(p => p.IsLatestVersion);}退货包裹;}

<块引用>

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

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

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

这对我来说很好.

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 official Nuget.core framework which source code is available here: https://github.com/NuGet/NuGet2

I am not using the NuGet package: https://www.nuget.org/packages/NuGet.Core/ But the source code found on GitHub to be able to do some debugging.

Note: I am using the version 2.11 and not the 2.13

I am able to download a package at a desired directory and update the packages.config file:

// ---- Download and install a package at a desired path ----
string packageID = "Newtonsoft.json";
var sourceUri = new Uri("https://packages.nuget.org/api/v2");

// Return an IPackage
var package = GetNugetPackage(packageID, sourceUri);

IPackageRepository sourceRepository = PackageRepositoryFactory.Default.CreateRepository(sourceUri.ToString());

string packagesPath = "../../TestFiles/packages";
PackageManager packageManager = new PackageManager(sourceRepository, packagesPath);

packageManager.InstallPackage(packageID, SemanticVersion.Parse(package.Version.ToFullString()));

// ---- Update the ‘packages.config’ file ----
var packageReferenceFile = new PackageReferenceFile("../../TestFiles/packages.config");

// Get the target framework of the current project to add --> targetframework="net452" attribute in the package.config file
var currentTargetFw = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(TargetFrameworkAttribute), false);
var targetFrameworkAttribute = ((TargetFrameworkAttribute[])currentTargetFw).FirstOrDefault();

// Update the packages.config file    
packageReferenceFile.AddEntry(package.GetFullName(), SemanticVersion.Parse(package.Version.ToFullString()), false, new FrameworkName(targetFrameworkAttribute.FrameworkName));

Now I need to update the .csproj and here is the tricky part...

Here's what I tried so far:

string csprojFilePath = "../../TestFiles/test.csproj";
var project = new MSBuildProjectSystem(csprojFilePath);

string pathToAnExistingNugetPackageDll = "../../TestFiles/packages/Newtonsoft.json/lib/net45/Newtonsoft.json.dll"

project.AddReference(pathToAnExistingNugetPackageDll, Stream.Null);
project.Save();

This piece of code update the .csproj file, it add a new reference node like this:

<Reference Include="Newtonsoft.json">
  <HintPath>..packagesNewtonsoft.jsonlib
et45Newtonsoft.json.dll</HintPath>      
</Reference>

But I need a complete reference node like this:

<Reference Include="Newtonsoft.json, Version=9.0.8, Culture=neutral, PublicKeyToken=b03f4f7d11d50a3a, processorArchitecture=MSIL">
  <HintPath>..packagesNewtonsoft.jsonlib
et45Newtonsoft.json.dll</HintPath>
  <Private>True</Private>
</Reference>

How can I do it ?

解决方案

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.

这篇关于如何以编程方式安装 NuGet 包?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆