[Nuget] Nuget API V3 使用筆記

以前曾經使用過Nuget V2 (NuGet.Core)來操作 nuget,因為需要所以改用 V3,這裡就紀錄使用方式

開發環境

VS 2017

NuGet.PackageManagement 4.9.3

安裝套件

Install-Package NuGet.PackageManagement

下載

Settings.LoadDefaultSettings(null):指定nuget.config的位置,不指定則使用預設(nuget.exe.config)

SettingsUtility.GetGlobalPackagesFolder(settings):預設快取位置,C:\Users\yao\.nuget\packages\

NullLogger.Instance:ILogger 實作,我不打算實作Log,所以使用內建的NullLogger

SourceCacheContext:快取

PackageDownloadContext:下載位置

SourceRepositoryProvider:倉儲位置為 nuget.config 的 packagesources 節點,https://docs.microsoft.com/zh-tw/nuget/reference/nuget-config-file#packagesources

PackageDownloader.GetDownloadResourceResultAsync:回傳 Stream,把它複製 FileStream 即可;因為有多個倉儲,只要下載到檔案,就離開迴圈

public static async Task DownloadAsync(string packageId, string version)
{
    var package = new PackageIdentity(packageId, NuGetVersion.Parse(version));
 
    var settings = Settings.LoadDefaultSettings(null);
    var globalFolder = SettingsUtility.GetGlobalPackagesFolder(settings);
 
    var logger = NullLogger.Instance;
    var cancelToken = CancellationToken.None;
 
    var sourceRepositoryProvider = new SourceRepositoryProvider(settings, Repository.Provider.GetCoreV3());
    var downloadFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Download");
    using (var cacheContext = new SourceCacheContext())
    {
        var downloadContext = new PackageDownloadContext(cacheContext, downloadFolder, true);
 
        var repositories = sourceRepositoryProvider.GetRepositories();
        foreach (var repository in repositories)
        {
            var downloadResult = await PackageDownloader.GetDownloadResourceResultAsync(repository,
                                                                                        package,
                                                                                        downloadContext,
                                                                                        globalFolder,
                                                                                        logger,
                                                                                        cancelToken);
 
            if (downloadResult != null)
            {
                var downloadFile = $@"{downloadFolder}\{package.Id}.{package.Version}.nupkg";
 
                using (var fileStream = File.Create(downloadFile))
                {
                    downloadResult.PackageStream.Seek(0SeekOrigin.Begin);
                    await downloadResult.PackageStream.CopyToAsync(fileStream);
                }
 
                break;
            }
        }
    }
}

 

取得所有依賴組件

public static async Task<ISet<PackageIdentity>> GetAllDependenciesAsync(string packageId,
                                                                        string version)
{
    var package = new PackageIdentity(packageId, NuGetVersion.Parse(version));
    var settings = Settings.LoadDefaultSettings(null);
    var nuGetFramework = NuGetFramework.AnyFramework;
    var logger = NullLogger.Instance;
    var cancelToken = CancellationToken.None;
    var sourceRepositoryProvider = new SourceRepositoryProvider(settings, Repository.Provider.GetCoreV3());
    var availablePackages = new HashSet<PackageIdentity>(PackageIdentityComparer.Default);
 
    using (var cacheContext = new SourceCacheContext())
    {
        var repositories = sourceRepositoryProvider.GetRepositories();
 
        await GetDependenciesAsync(package,
                                   nuGetFramework,
                                   cacheContext,
                                   logger,
                                   repositories,
                                   availablePackages,
                                   cancelToken);
    }
 
    return availablePackages;
}

 

這是依各遞迴方法,主要是dependencyInfoResource.ResolvePackage 這個方法取得依賴組件,dependencyInfo.Dependencies 則是存放結果。

private static async Task GetDependenciesAsync(PackageIdentity package,
                                               NuGetFramework framework,
                                               SourceCacheContext cacheContext,
                                               ILogger logger,
                                               IEnumerable<SourceRepository> repositories,
                                               ISet<PackageIdentity> availablePackages,
                                               CancellationToken cancellation)
{
    if (availablePackages.Contains(package))
    {
        return;
    }
 
    foreach (var sourceRepository in repositories)
    {
        var dependencyInfoResource = await sourceRepository.GetResourceAsync<DependencyInfoResource>();
        var dependencyInfo = await dependencyInfoResource.ResolvePackage(package,
                                                                         framework,
                                                                         cacheContext,
                                                                         logger,
                                                                         cancellation);
 
        if (dependencyInfo != null)
        {
            if (!availablePackages.Contains(dependencyInfo))
            {
                availablePackages.Add(dependencyInfo);
                foreach (var dependency in dependencyInfo.Dependencies)
                {
                    var dependPackage = new PackageIdentity(dependency.Id, dependency.VersionRange.MinVersion);
                    await GetDependenciesAsync(dependPackage,
                                               framework,
                                               cacheContext,
                                               logger,
                                               repositories,
                                               availablePackages, cancellation);
                }
            }
 
            break;
        }
    }
}

 

搜尋組件

大部分的用法都跟上述一樣,差在這裡是透過 SearchAsync 方法來取得相關組件

var searchResource = await sourceRepository.GetResourceAsync<PackageSearchResource>();
var metadatas = await searchResource.SearchAsync(null,
                                                 new SearchFilter(false),
                                                 skip,
                                                 take,
                                                 logger,
                                                 cancelToken);

完整範例在 GetAllPackagesAsync 方法,是呼叫另一各遞迴方法每次搜尋 10 筆組件

https://github.com/yaochangyu/sample.dotblog/blob/master/Nuget/NugetV3/Simple.NugetV3/NugetManager.cs
 

參考

https://martinbjorkstrom.com/posts/2018-09-19-revisiting-nuget-client-libraries
 

 

若有謬誤,煩請告知,新手發帖請多包涵


Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET

Image result for microsoft+mvp+logo