如何以编程方式安装 NuGet 包?

How to programmatically install a NuGet package?(如何以编程方式安装 NuGet 包?)
本文介绍了如何以编程方式安装 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 包?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

DispatcherQueue null when trying to update Ui property in ViewModel(尝试更新ViewModel中的Ui属性时DispatcherQueue为空)
Drawing over all windows on multiple monitors(在多个监视器上绘制所有窗口)
Programmatically show the desktop(以编程方式显示桌面)
c# Generic Setlt;Tgt; implementation to access objects by type(按类型访问对象的C#泛型集实现)
InvalidOperationException When using Context Injection in ASP.Net Core(在ASP.NET核心中使用上下文注入时发生InvalidOperationException)
LINQ many-to-many relationship, how to write a correct WHERE clause?(LINQ多对多关系,如何写一个正确的WHERE子句?)