如何以编程方式安装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文件:

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

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

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

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

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

  ..\packages\Newtonsoft.json\lib\net45\Newtonsoft.json.dll  

但我需要一个完整的 reference节点,如下所示:

  ..\packages\Newtonsoft.json\lib\net45\Newtonsoft.json.dll True  

我该怎么做 ?

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

因此,要在给定的.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

如果你想测试它,你可能会调整一下。

这对我来说很好。

(假设您自己编写代码生成器)

我不确定这是最好的解决方案,但你可以尝试这样的事情:

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

这将通过加载程序集增加一些开销,但可能会完成这项工作。