NuGetFetch — download/extract/query NuGet packages from .NET
A small NuGet client. Package NuGetFetch, namespace NuGetFetch. AOT-compatible
(System.Text.Json source-gen, no reflection). Do NOT reach for the official
NuGet.Protocol/NuGet.Client types (SourceRepository, FindPackageByIdResource,
PackageMetadataResource, …) — none of those exist here.
Core pattern (bring your own HttpClient)
using NuGetFetch;
HttpClient http = new(); // YOU own it. NuGetClient has no parameterless ctor.
NuGetClient client = new(http); // pass the HttpClient in.
string? latest = await client.GetLatestVersionAsync("Newtonsoft.Json"); // "13.0.4" or null
IReadOnlyList<string> all = await client.GetVersionsAsync("Newtonsoft.Json"); // ascending; all[0] is oldest
string? v = await client.ResolveVersionPatternAsync("Newtonsoft.Json", "12.0.*"); // "12.0.3"
await client.DownloadToFileAsync("Newtonsoft.Json", "13.0.3", "/tmp/n.nupkg"); // write .nupkg to disk
using Stream s = await client.DownloadAsync("Newtonsoft.Json", "13.0.3"); // or get a stream
Extraction is a SEPARATE static class (not a NuGetClient method)
string dir = PackageExtractor.Extract("/tmp/n.nupkg", "/tmp/out"); // from a file
string dir2 = await PackageExtractor.ExtractAsync(stream, "/tmp/out"); // from a DownloadAsync stream
bool ok = PackageExtractor.IsValidPackage(dir);
bool hasDlls = PackageExtractor.HasManagedLibraries(dir);
PackageIdentity? id = PackageExtractor.ParsePackageReference("Newtonsoft.Json@13.0.1"); // .Id, .Version
Search is a SEPARATE class
SearchService search = new(http);
IReadOnlyList<SearchResult> r = await search.SearchByPrefixAsync("Newtonsoft", take: 5); // r[i].Id
IReadOnlyList<SearchResult> q = await search.SearchAsync("json", take: 20, prerelease: false);
Gotchas (where intuition is wrong)
- No internal HttpClient.
new NuGetClient()does not exist; alwaysnew NuGetClient(http). Same forSearchService(http). Reuse oneHttpClient. NuGetClient.NormalizeVersion(v)is STATIC ("1.0.0.0"->"1.0.0"), not an instance method.- Extraction/parse helpers are on
PackageExtractor(static), not onNuGetClient. - Parsing an
"id@version"string: callPackageExtractor.ParsePackageReference(returns aPackageIdentitywith.Id/.Version) — do NOT hand-split on@. The library owns this shape; reach for the method, notstring.Split. - Checking for managed assemblies:
PackageExtractor.HasManagedLibraries(dir)(bool) after extracting — there is noNuGetClientequivalent. GetVersionsAsyncis already in ascending NuGet version order — oldest islist[0], newest islist[^1]. Do NOT re-sort the list yourself: a naive string/OrderBysort is wrong ("10.0.1"sorts before"3.5.8"lexically). Trust the returned order; useGetLatestVersionAsyncfor "latest stable".- Async, Task-returning,
*Asyncsuffix on every network call; nullable returns where a package/version may not exist (GetLatestVersionAsync,ResolveVersionPatternAsync).
After it builds: show your work
Show the final program and name the NuGetFetch calls used (e.g. GetLatestVersionAsync,
PackageExtractor.IsValidPackage). This library shadows the official NuGet client, so
surfacing the calls proves you used NuGetFetch — not a hallucinated NuGet.Protocol shape.