Reputation: 6831
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)
Upvotes: 1
Views: 7191
Reputation: 91
My solution will get you dll and neGetproj file
public static void InstallDlls()
{
//ID of the package to be looked
string package = "EntityFramework";
//Connect to the official package repository IPackageRepository
IPackageRepository repo = PackageRepositoryFactory.Default.CreateRepository("https://nuget.testsys.com/nuget");
string path = @"YourTargetPath";
//Initialize the package manager string path = <PATH_TO_WHERE_THE_PACKAGES_SHOULD_BE_INSTALLED>
PackageManager packageManager = new PackageManager(repo, path);
//Download and unzip the package
packageManager.InstallPackage(package, NuGet.SemanticVersion.Parse("5.0.0"));
}
Upvotes: 0
Reputation: 12959
Upvotes: 7
Reputation: 6831
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.
Upvotes: 8