When using the v6.3 Nuget.Packaging and NuGet.PackageManagement libaries, I am unable to install packages like I can when using v.4.0 equivalent.
It seems to be releated to my PluginProject.InstallPackageAsync override, v6 throws a null refernce exception but not with v4. Not calling the base.InstallPackagesAsync fails to install any packages in my folder so im sure its key.
// Class is derived from FolderNuGetProject and method overidden
public override async Task<bool> InstallPackageAsync(PackageIdentity packageIdentity, DownloadResourceResult downloadResourceResult,
INuGetProjectContext nuGetProjectContext, CancellationToken token)
{
var result = await base.InstallPackageAsync(packageIdentity, downloadResourceResult, nuGetProjectContext, token);
await _packagesConfigProject.InstallPackageAsync(packageIdentity, downloadResourceResult, nuGetProjectContext, token);
return result;
}
Even when using the FolderNuGetProject directly, it throws - so I have found the source of the error need to debug the source to understand why... nuGetProjectContext.PackageExtractionContext is null.
Detail
I writing an app which has plugins downloadable from nuget, which can then be dynamically loaded into my application - similair to this interesting talk.
I derive my class from the NuGet.ProjectManagement.FolderNuGetProject, however files are not installed after calling NuGetPackageManager.InstallPackageAsync with my custom folder project, only packages.config is updated per below:
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Unified.Mqtt.Pattern" version="1.0.3" targetFramework="netstandard2.0" />
</packages>
But no files in the directory other than that:
PS C:\ProgramData\unified.msp> dir
Directory: C:\ProgramData\unified.msp
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 07/08/2022 11:07 156 packages.config
The Project class is below:
public class PluginProject : FolderNuGetProject
{
private readonly PackagesConfigNuGetProject packagesConfigProject;
public PluginProject(string root) : base(root)
{
this.packagesConfigProject = new PackagesConfigNuGetProject(root, new Dictionary<string, object>()
{
{ "TargetFramework", NuGetFramework.AnyFramework },
{ "Name", "My.Package.Installer" }
});
}
public override Task<IEnumerable<PackageReference>> GetInstalledPackagesAsync(CancellationToken cancellationToken)
{
return this.packagesConfigProject.GetInstalledPackagesAsync(cancellationToken);
}
public override Task<bool> InstallPackageAsync(PackageIdentity packageIdentity, DownloadResourceResult downloadResourceResult,
INuGetProjectContext nuGetProjectContext, CancellationToken token)
{
// THIS LINE THROWS NULL REFERENCE WITH v6, BUT NOT v4
var result = await DeletePackage(packageIdentity, nuGetProjectContext, token);
await
packagesConfigProject.UninstallPackageAsync(packageIdentity, nuGetProjectContext, token);
return result;
}
}
And the overall plugin manager is below (which scaffolds everything together into the NuGetPackangeManager method calls. It does list installed packages, and can install (ableit without the actual file contents):
public class NugetPluginManager
{
private readonly IOptions<NugetPluginManagerSettings> settings;
private readonly LoggerAdapter logger;
public NugetPluginManager(IOptions<NugetPluginManagerSettings> settings, ILogger<NugetPluginManager> logger)
{
this.settings = settings;
this.logger = new LoggerAdapter(logger);
}
private static (SourceRepository Repository, List<Lazy<INuGetResourceProvider>> Providers) GetRepository(string repositoryUrl)
{
var providers = new List<Lazy<INuGetResourceProvider>>();
providers.AddRange(Repository.Provider.GetCoreV3());
var packageSource = new PackageSource(repositoryUrl);
var repository = new SourceRepository(packageSource, providers);
if(packageSource.SourceUri.Scheme != Uri.UriSchemeHttps)
throw new ArgumentException($"{repositoryUrl} is not https.", nameof(repositoryUrl));
return (repository, providers);
}
public async Task<IEnumerable<PackageReference>> GetInstalledPackages(CancellationToken cancellationToken = default)
{
var commonApplicationDataPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
var rootAppPath = Path.Combine(commonApplicationDataPath, "unified.msp");
var packagesPath = Path.Combine(rootAppPath, "packages");
var project = new PluginProject(rootAppPath);
return await project.GetInstalledPackagesAsync(cancellationToken);
}
public async Task Install(string repositoryUrl, string packageName, string version, bool includeDependencies,
bool includePreRelease, CancellationToken cancellationToken = default)
{
var (repository, providers) = GetRepository(repositoryUrl);
var commonApplicationDataPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
var rootAppPath = Path.Combine(commonApplicationDataPath, "unified.msp");
var packagesPath = Path.Combine(rootAppPath, "packages");
var project = new PluginProject(rootAppPath);
var defaultSettings = Settings.LoadDefaultSettings(rootAppPath, null, new XPlatMachineWideSetting());
// Create the package manager - TODO: https://github.com/NuGet/Home/issues/8479
#pragma warning disable CS0618 // Type or member is obsolete
var repositoryProvider = new SourceRepositoryProvider(defaultSettings, providers);
#pragma warning restore CS0618 // Type or member is obsolete
var packageManager = new NuGetPackageManager(repositoryProvider, defaultSettings, packagesPath)
{
PackagesFolderNuGetProject = project
};
var dependencyBehaviour = includeDependencies ? DependencyBehavior.Lowest : DependencyBehavior.Ignore;
var resolutionContext =
new ResolutionContext(dependencyBehaviour, includePreRelease, false, VersionConstraints.None);
var projectContext = new EmptyNuGetProjectContext();
await packageManager.InstallPackageAsync(
packageManager.PackagesFolderNuGetProject,
new PackageIdentity(packageName, NuGetVersion.Parse(version)),
resolutionContext,
projectContext,
repository,
Array.Empty<SourceRepository>(),
cancellationToken);
}
}
