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.mspMode 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) { return this.packagesConfigProject .InstallPackageAsync(packageIdentity, downloadResourceResult, nuGetProjectContext, token); }}
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); }}