I found example code to work with nuget api.
My task is show full name and download link.
Here is code:
static void Main(string[] args)
{
//ID of the package to be looked up
string packageID = "EntityFramework";
//Connect to the official package repository
IPackageRepository repo = PackageRepositoryFactory.Default.CreateRepository("https://packages.nuget.org/api/v2");
//Get the list of all NuGet packages with ID 'EntityFramework'
List<IPackage> packages = repo.FindPackagesById(packageID).ToList();
//Filter the list of packages that are not Release (Stable) versions
packages = packages.Where(item => (item.IsReleaseVersion() == false)).ToList();
//Iterate through the list and print the full name of the pre-release packages to console
foreach (IPackage p in packages)
{
Console.WriteLine($"{p.GetFullName()};");
}
}
When I debug, I see link to download, but how can I get this value?
I attached screens for debug info.
Debug info
Missing param
You can do this to get the link to download :
foreach (var p in packages.ConvertAll(o => (DataServicePackage)o))
{
Console.WriteLine($"{p.GetFullName()};");
Console.WriteLine(p.DownloadUrl.ToString())
}
Related
Is there a way, either textual or graphical, to view the hierarchy of dependencies between NuGet packages?
If you're using the new .csproj, you could get all dependencies with reference in here (after project built):
{ProjectDir}\obj\project.assets.json
Like #neil-barnwell solution, but works with NuGet.Core 2.7+
Install-Package NuGet.Core
Here is the code
using System;
using System.Linq;
using System.Runtime.Versioning;
using System.IO;
using NuGet;
public class Program
{
public static void Main(string[] args)
{
var frameworkName = new FrameworkName(".NETFramework, Version=4.0");
// var packageSource = "https://www.nuget.org/api/v2/";
var packageSource = Path.Combine(Environment.GetEnvironmentVariable("LocalAppData"), "NuGet", "Cache");
var repository = PackageRepositoryFactory.Default.CreateRepository(packageSource);
const bool prerelease = false;
var packages = repository.GetPackages()
.Where(p => prerelease ? p.IsAbsoluteLatestVersion : p.IsLatestVersion)
.Where(p => VersionUtility.IsCompatible(frameworkName, p.GetSupportedFrameworks()));
foreach (IPackage package in packages)
{
GetValue(repository, frameworkName, package, prerelease, 0);
}
Console.WriteLine();
Console.WriteLine("Press Enter...");
Console.ReadLine();
}
private static void GetValue(IPackageRepository repository, FrameworkName frameworkName, IPackage package, bool prerelease, int level)
{
Console.WriteLine("{0}{1}", new string(' ', level * 3), package);
foreach (PackageDependency dependency in package.GetCompatiblePackageDependencies(frameworkName))
{
IPackage subPackage = repository.ResolveDependency(dependency, prerelease, true);
GetValue(repository, frameworkName, subPackage, prerelease, level + 1);
}
}
}
It is also possible to write code against the API in NuGet.Core. Install it via NuGet:
install-package nuget.core
Then you can get a repository object and walk the graph. Here's a sample app I just built:
using System;
using System.Collections.Generic;
using System.Linq;
using NuGet;
namespace ConsoleApplication2
{
class Program
{
static void Main()
{
var repo = new LocalPackageRepository(#"C:\Code\Common\Group\Business-Logic\packages");
IQueryable<IPackage> packages = repo.GetPackages();
OutputGraph(repo, packages, 0);
}
static void OutputGraph(LocalPackageRepository repository, IEnumerable<IPackage> packages, int depth)
{
foreach (IPackage package in packages)
{
Console.WriteLine("{0}{1} v{2}", new string(' ', depth), package.Id, package.Version);
IList<IPackage> dependentPackages = new List<IPackage>();
foreach (var dependency in package.Dependencies)
{
dependentPackages.Add(repository.FindPackage(dependency.Id, dependency.VersionSpec.ToString()));
}
OutputGraph(repository, dependentPackages, depth += 3);
}
}
}
}
In my case, this app outputs something like this:
MyCompany.Castle v1.1.0.3
Castle.Windsor v2.5.3
Castle.Core v2.5.2
MyCompany.Common v1.1.0.6
CommonServiceLocator v1.0
MyCompany.Enum v1.1.0.7
MyCompany.Common v1.1.0.6
CommonServiceLocator v1.0
MyCompany.Enum v1.1.0.7
MyCompany.Enum v1.1.0.7
MyCompany.Versioning v1.3
Castle.Core v2.5.2
Castle.Windsor v2.5.3
Castle.Core v2.5.2
CommonServiceLocator v1.0
NUnit v2.5.10.11092
RhinoMocks v3.6
I've found a nice NPM package to print the dependency tree into console. Of course if you don't mind using/installing NPM/Node.JS.
Considering other solutions, this is the most simple one, you don't need to write your own code or register something, and you get just such dependency tree as you expect. But it works only with packages.config format.
I can't believe this functionality is absent in free Visual Studio editions or nuget.exe too.
I Can Has .NET Core (GitHub repository) produces nice graphs of NuGet dependencies along with a Graphviz representation. And as its name implies, you also get .NET Core compatibility information for free.
If you prefer to run it locally on your computer, I Can Has .NET Core also offers a console mode.
I add a compatible solution with the latest version of nuget-core
install-package nuget.core
This is the console App to get the dependencies graph
class Program
{
static void Main()
{
Console.Write("Enter the local repo folder: ");
var repoFolder = Console.ReadLine();
var repo = new LocalPackageRepository(repoFolder);
IQueryable<IPackage> packages = repo.GetPackages();
OutputGraph(repo, packages, 0);
}
static void OutputGraph(LocalPackageRepository repository, IEnumerable<IPackage> packages, int depth)
{
foreach (IPackage package in packages)
{
Console.WriteLine("{0}{1} v{2}", new string(' ', depth), package.Id, package.Version);
IList<IPackage> dependentPackages = new List<IPackage>();
foreach (var dependencySet in package.DependencySets)
{
foreach (var dependency in dependencySet.Dependencies)
{
var dependentPackage = repository.FindPackage(dependency.Id, dependency.VersionSpec, true, true);
if (dependentPackage != null)
{
dependentPackages.Add(dependentPackage);
}
}
}
OutputGraph(repository, dependentPackages, depth + 3);
}
}
}
Package Visualized from NuGet 1.4 should work. See http://docs.nuget.org/docs/release-notes/nuget-1.4
Since this is an old question, it is important to note the following:
This is a built-in feature in the new csproj format. In Visual Studio 2017 and up, open the Solution Explorer and you can find you packages like:
{Your project}->Dependencies->Packages
You can open each NuGet dependency tree and run with it recursively, effectively seeing not only the dependency tree for specific packages, but also which NuGet packages your project actually installs.
Another option you have is to use the nuget-deps-tree npm package.
It supports both the packages.config format and the newer assets format used by .NET projects.
FYI, MyGet.org has this kind of visualization built-in. You can view dependency graphs on the Feed Details page.
https://github.com/mikehadlow/AsmSpy using this to identify assembly version across a project
I have successfully started a console app solution in Visual Studio 2019, in C#, and have downloaded and installed the package DocumentFormat.OpenXML.DotNet.Core from NuGet. Since DocumentFormat.OpenXML does not play with .NET Core, I cannot use that. I have also successfully attached the package to the solution, and it appears in the Solution Explorer with no alerts. (Same method I have used in the past with other packages.)
This package is supposed to give my solution access to the OpenXML functionality, but I cannot get my program to recognize it.
I have tried inserting a using statement for DocumentFormat, but I get an error that the using statement is not necessary - and then it asks if I am missing a using statement or assembler reference.
I have tried changing the namespace to DocumentFormat, but then I have to add all the classes and all the functions, which it seems to me is the entire purpose of the package.
Here is the code (it's sample code just to get this working):
using System;
using DocumentFormat;
using S = DocumentFormat.OpenXml.Spreadsheet.Sheets;
using E = DocumentFormat.OpenXml.OpenXmlElement;
using A = DocumentFormat.OpenXml.OpenXmlAttribute;
namespace ConsoleApp1
{
class Program
{
static void ReadExcelFile()
{
try
{
//Lets open the existing excel file and read through its content . Open the excel using openxml sdk
using (SpreadsheetDocument doc = SpreadsheetDocument.Open("testdata.xlsx", false))
{
//create the object for workbook part
WorkbookPart workbookPart = doc.WorkbookPart;
Sheets thesheetcollection = workbookPart.Workbook.GetFirstChild<Sheets>();
StringBuilder excelResult = new StringBuilder();
//using for each loop to get the sheet from the sheetcollection
foreach (Sheet thesheet in thesheetcollection)
{
excelResult.AppendLine("Excel Sheet Name : " + thesheet.Name);
excelResult.AppendLine("----------------------------------------------- ");
//statement to get the worksheet object by using the sheet id
Worksheet theWorksheet = ((WorksheetPart)workbookPart.GetPartById(thesheet.Id)).Worksheet;
SheetData thesheetdata = (SheetData)theWorksheet.GetFirstChild<SheetData>();
foreach (Row thecurrentrow in thesheetdata)
{
foreach (Cell thecurrentcell in thecurrentrow)
{
//statement to take the integer value
string currentcellvalue = string.Empty;
if (thecurrentcell.DataType != null)
{
if (thecurrentcell.DataType == CellValues.SharedString)
{
int id;
if (Int32.TryParse(thecurrentcell.InnerText, out id))
{
SharedStringItem item = workbookPart.SharedStringTablePart.SharedStringTable.Elements<SharedStringItem>().ElementAt(id);
if (item.Text != null)
{
//code to take the string value
excelResult.Append(item.Text.Text + " ");
}
else if (item.InnerText != null)
{
currentcellvalue = item.InnerText;
}
else if (item.InnerXml != null)
{
currentcellvalue = item.InnerXml;
}
}
}
}
else
{
excelResult.Append(Convert.ToInt16(thecurrentcell.InnerText) + " ");
}
}
excelResult.AppendLine();
}
excelResult.Append("");
Console.WriteLine(excelResult.ToString());
Console.ReadLine();
}
}
}
catch (Exception)
{
}
}
}
}
I have refreshed the package,
I have started a new solution and added the package to it before typing anything in the code window,
I have tried updating and reinstalling both in the NuGet Package Manager Console and in the Manage NuGet Packages for Solution window.
Can someone please tell me what I'm missing?
Thanks in advance,
DJ
Not sure how you determined that the Open XML SDK as provided in the DocumentFormat.OpenXml NuGet package "does not play with .NET Core". As a contributor to the Open XML SDK, I can confirm that it definitely does play with .NET Core and you can clone my CodeSnippets GitHub repository to test this yourself. That repository contains a solution with multiple projects, a few of which use .NET Core (e.g., the CodeSnippets library, which targets netstandard2.0, and the CodeSnippets.Tests library, which targets netcoreapp3.0).
The DocumentFormat.OpenXml.DotNet.Core NuGet package that you use was last updated on July 30, 2016, i.e., almost four years ago. You should really replace this with the official DocumentFormat.OpenXml NuGet package.
I am trying to extract a dll from a nuget package programatically and load the dll at runtime.
I want to avoid using any command line tools - I want my program to be completely self contained, and not rely on external executables.
I am trying to use the various nuget.client nuget packages listed at https://www.nuget.org/profiles/nuget, but there is no documentation for them whatsoever and I can't work out how.
I have the nupkg, and I am able to work out the location of the dll in the nupkg via a PackageReader, but I don't know how to extract the nupkg so that I can get the file out.
Edit
Thanks to the people who have pointed out that a nupkg is just a zip. I've now done the following:
var archive = new ZipArchive(downloadResourceResult.PackageStream);
var entry = archive.GetEntry(dllPath);
var assemblyLoadContext = new System.Runtime.Loader.AssemblyLoadContext(null, isCollectible: true);
var assembly = assemblyLoadContext.LoadFromStream(entry.Open());
However this throws a NotSupportedException with the following stack trace
System.IO.Compression.DeflateStream.get_Length() at System.Runtime.Loader.AssemblyLoadContext.LoadFromStream(Stream assembly, Stream assemblySymbols) at System.Runtime.Loader.AssemblyLoadContext.LoadFromStream(Stream assembly)
Here is a full method to download a nuget package and load it. It's just a POC - you'll want to configure it for your use case.
public async Task<Assembly> LoadFromNuget(string id, string version, string? nugetFeedUrl = null, CancellationToken cancellationToken = default)
{
var repository = Repository.Factory.GetCoreV3(nugetFeedUrl ?? "https://api.nuget.org/v3/index.json");
var downloadResource = await repository.GetResourceAsync<DownloadResource>();
if (!NuGetVersion.TryParse(version, out var nuGetVersion))
{
throw new Exception($"invalid version {version} for nuget package {id}");
}
using var downloadResourceResult = await downloadResource.GetDownloadResourceResultAsync(
new PackageIdentity(id, nuGetVersion),
new PackageDownloadContext(new SourceCacheContext()),
globalPackagesFolder: Path.GetTempDirectory(),
logger: _nugetLogger,
token: cancellationToken);
if (downloadResourceResult.Status != DownloadResourceResultStatus.Available)
{
throw new Exception($"Download of NuGet package failed. DownloadResult Status: {downloadResourceResult.Status}");
}
var reader = downloadResourceResult.PackageReader;
var archive = new ZipArchive(downloadResourceResult.PackageStream);
var lib = reader.GetLibItems().First()?.Items.First();
var entry = archive.GetEntry(lib);
using var decompressed = new MemoryStream();
entry.Open().CopyTo(decompressed);
var assemblyLoadContext = new System.Runtime.Loader.AssemblyLoadContext(null, isCollectible: true);
decompressed.Position = 0;
return assemblyLoadContext.LoadFromStream(decompressed);
}
You'll have to implement or use a version of the Nuget ILogger to download the nupkg.
You can rename the nuget extension to zip extension and should be able to extract to folder.
Now, you can get the dlls from the extracted folder.
I created one console application to create visual studio project pragmatically, here i am not able install Nuget packages, always
var componentModel = (IComponentModel)Package.GetGlobalService(typeof(SComponentModel)); statement returns null values. for your reference i added my code below. Help me to resolve this issue.
static void Main(string[] args)
{
//InstallNuGetPackages.InstallNuGet("");
string ProjectName = "WebAPIProj";
string SolutionName = "EmptyTemplate";
System.Type type = System.Type.GetTypeFromProgID("VisualStudio.DTE.11.0");
Object obj = System.Activator.CreateInstance(type, true);
EnvDTE.DTE dte = (EnvDTE.DTE)obj;
dte.MainWindow.Visible = true; // optional if you want to See VS doing its thing
// create a new solution
dte.Solution.Create("C:\\"+ SolutionName + "\\", SolutionName);
var solution = dte.Solution;
// create a C# WinForms app
solution.AddFromTemplate(#"C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\ProjectTemplatesCache\CSharp\Web\1033\EmptyWebApplicationProject40\EmptyWebApplicationProject40.vstemplate",
#"C:\NewSolution\"+ ProjectName, ProjectName);
InstallNuGetPackages.InstallNuGet(dte);
foreach (var p in dte.Solution.Projects)
{
InstallNuGetPackages.InstallNuGet((Project)p, "Microsoft.AspNet.WebApi version1.1");
}
// save and quit
dte.ExecuteCommand("File.SaveAll");
dte.Quit();
}
Code to install Nuget Packages
public bool InstallNuGetPackage(Project project, string package)
{
bool installedPkg = true;
try
{
var componentModel = (IComponentModel)Package.GetGlobalService(typeof(SComponentModel)); //Always this statement returns null
IVsPackageInstallerServices installerServices = componentModel.GetService();
if (!installerServices.IsPackageInstalled(project, package))
{
var installer = componentModel.GetService();
installer.InstallPackage(null, project, package, (System.Version)null, false);
}
}
catch (Exception ex)
{
installedPkg = false;
}
return installedPkg;
}
(Turned this into an answer for better readability and more room)
created one console application - you only have access to the ServiceProvider from Visual Studio if you run your code inside of it, i.e. from an extension and/or package.
Running this from a console application cannot work. Visual Studio internally does a lot more setup for all the services and general environment than creating an instance of DTE.
To persue your route, although I'm not sure how feasible that is, invoke nuget.exe or NuGet.Core code to achieve similar.
I'm looking for a way to run code by executing the following steps:
Receiving a list of NuGet packages (a list of tuples ("package name", "package version", "path to main class").
Retrieving them in a local directory (cf code sample #1)
Loading them in my program at run-time
Running the main classes by introspection (cf code sample #2)
By now I am struggling with the third step. I can't find out how to load my package at run-time.
My main question are:
How can I find out in which folders were stored the retrieved packages?
How can I load the content of those directories into my program?
Code Sample #1:
private static void getPackageByNameAndVersion(string packageID, string version)
{
IPackageRepository repo =
PackageRepositoryFactory.Default
.CreateRepository("https://packages.nuget.org/api/v2");
string path = "C:/tmp_repo";
PackageManager packageManager = new PackageManager(repo, path);
Console.WriteLine("before dl pkg");
packageManager.InstallPackage(packageID, SemanticVersion.Parse(version));
}
Code sample #2:
private static void loadByAssemblyNameAndTypeName(string assemblyName, string typeName)
{
AppDomain isolationAppDomain = AppDomain.CreateDomain("tmp");
object a = isolationAppDomain.CreateInstanceAndUnwrap(assemblyName, typeName);
Type x = a.GetType();
MethodInfo m = x.GetMethod("Main");
m.Invoke(a, new object[] { });
}
Grab a cup of coffee :)
Downloading the nuget package?
Nuget.Core (nuget package) is a good choice, and here is a snippet of code that I have that should be able to download a nuget package by id and version
var repo = PackageRepositoryFactory.Default
.CreateRepository("https://packages.nuget.org/api/v2");
string path = "c:\\temp";
var packageManager = new PackageManager(repo, path);
packageManager.PackageInstalled += PackageManager_PackageInstalled;
var package = repo.FindPackage("packageName", SemanticVersion.Parse("1.0.0"));
if (package != null)
{
packageManager.InstallPackage(package, false, true);
}
Notice that I plugged an event handler to the PackageInstalled event of the PackageManager class.
How do we load an assembly in an isolated app domain?
Since reflection API does not provide a way to load an assembly in a specific domain, We will create a proxy class that act as a loader in our isolated domain:
public class TypeProxy : MarshalByRefObject
{
public Type LoadFromAssembly(string assemblyPath, string typeName)
{
try
{
var asm = Assembly.LoadFile(assemblyPath);
return asm.GetType(typeName);
}
catch (Exception) { return null; }
}
}
And now, is how to put it all together?
Here comes the complex part:
private static void PackageManager_PackageInstalled(object sender,
PackageOperationEventArgs e)
{
var files = e.FileSystem.GetFiles(e.InstallPath, "*.dll", true);
foreach (var file in files)
{
try
{
AppDomain domain = AppDomain.CreateDomain("tmp");
Type typeProxyType = typeof(TypeProxy);
var typeProxyInstance = (TypeProxy)domain.CreateInstanceAndUnwrap(
typeProxyType.Assembly.FullName,
typeProxyType.FullName);
var type = typeProxyInstance.LoadFromAssembly(file, "<KnownTypeName>");
object instance =
domain.CreateInstanceAndUnwrap(type.Assembly.FullName, type.FullName);
}
catch (Exception ex)
{
Console.WriteLine("failed to load {0}", file);
Console.WriteLine(ex.ToString());
}
}
}
Notice that this method is the event handler that gets executed after downloading the nuget package
Also
Note that you will need to replace <KnownTypeName> with the expected type name coming from the assembly (or maybe run a discovery of all public types in the assembly)
Worth noting that I haven't executed this code myself and cannot guarantee that it will work out of the box, and still might need some tweaking. but Hopefully it is the concept that allows you to solve the problem.
Don't do that! You are probably trying to load NuGet content at a customers computer to save some space on distribution of your software. Isn't it that?
The common recommended approach is to download the NuGet content as the second step of an automated build (after downloading the source code), build the software and run the automated tests with the NuGet content you have downloaded. And then distribute the build with the NuGet content you have tested as the complex whole unit.