Yair Halberstadt
Yair Halberstadt

Reputation: 6831

Extract a dll from a nuget package using nuget.client

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

Answers (3)

samy nathan
samy nathan

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

Venkataraman R
Venkataraman R

Reputation: 12959

  1. You can rename the nuget extension to zip extension and should be able to extract to folder. Renaming Nuget extension to zip extension
  2. Now, you can get the dlls from the extracted folder.

enter image description here

Upvotes: 7

Yair Halberstadt
Yair Halberstadt

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

Related Questions