如何配置NuGet Client SDK指定特定目标框架?
我有一段代码可实现将NuGet包及其依赖项下载至指定文件夹,但这段代码会下载所有受支持的.NET版本(如.NET Standard 2.1、UWP、net45等)的二进制文件。请问如何配置它,使其仅下载适用于特定目标框架(例如.NET 6.0)的包版本?
补充说明:额外请教如何在运行时动态加载目标包所需的程序集,若需修改NuGet以包含json.deps也可接受。
现有代码示例
public async Task<HashSet<PackageIdentity>> InstallPackageAndDependenciesAsync(PackageIdentity identity) { bool allowUnlisted = false; bool includePrelease = true; try { ResolutionContext resolutionContext = new ResolutionContext( DependencyBehavior.Lowest, includePrelease, allowUnlisted, VersionConstraints.ExactMajor | VersionConstraints.ExactMinor); INuGetProjectContext projectContext = new BlankProjectContext(Settings.Settings, new NuGetCustomLogger()); var installActions = await LocalNuGetPackageManager.PreviewInstallPackageAsync( LocalNuGetPackageManager.PackagesFolderNuGetProject, identity, resolutionContext, projectContext, new[] { RemoteNuGetFeed }, Array.Empty<SourceRepository>(), CancellationToken.None); var sourceCache = new SourceCacheContext(); await LocalNuGetPackageManager.ExecuteNuGetProjectActionsAsync(LocalNuGetPackageManager.PackagesFolderNuGetProject, installActions, projectContext, sourceCache, CancellationToken.None); return new HashSet<PackageIdentity>(installActions.Select(action => action.PackageIdentity)); } catch (Exception ex) { throw; } }
一、仅下载指定目标框架的NuGet包
要实现只下载对应.NET 6.0的包,核心是让NuGet在解析依赖时只筛选兼容指定框架的包版本,具体修改如下:
定义目标框架
先明确要适配的目标框架:var targetFramework = FrameworkName.Parse("net6.0"); var targetFrameworks = new[] { targetFramework };自定义NuGet项目类
默认的PackagesFolderNuGetProject未指定目标框架,需要创建自定义类来暴露目标框架信息:public class TargetedPackagesFolderNuGetProject : PackagesFolderNuGetProject { private readonly IEnumerable<FrameworkName> _targetFrameworks; public TargetedPackagesFolderNuGetProject(string packagesPath, IEnumerable<FrameworkName> targetFrameworks) : base(packagesPath) { _targetFrameworks = targetFrameworks; } public override IEnumerable<FrameworkName> GetTargetFrameworks() { return _targetFrameworks; } }修改原代码逻辑
替换原有项目实例,并给ResolutionContext绑定目标框架,确保依赖解析时只匹配指定框架:// 替换默认的项目实例 var targetedProject = new TargetedPackagesFolderNuGetProject(LocalNuGetPackageManager.PackagesFolder, targetFrameworks); // 初始化带目标框架的解析上下文 var resolutionContext = new ResolutionContext( DependencyBehavior.Lowest, includePrelease, allowUnlisted, VersionConstraints.ExactMajor | VersionConstraints.ExactMinor) { TargetFrameworks = targetFrameworks };后续在
PreviewInstallPackageAsync和ExecuteNuGetProjectActionsAsync方法中,用targetedProject替代原来的PackagesFolderNuGetProject即可。调整后,NuGet会只下载与.NET 6.0兼容的包二进制文件,不再包含其他无关框架的内容。
二、运行时动态加载程序集
结合deps.json和AssemblyLoadContext可以实现依赖的正确加载,步骤如下:
确保保留deps.json文件
NuGet默认会下载包的完整内容,其中包含deps.json,只需确保解压包时不排除该文件即可。自定义AssemblyLoadContext
基于deps.json的依赖信息来加载程序集:public class NuGetAssemblyLoadContext : AssemblyLoadContext { private readonly DependencyContext _dependencyContext; private readonly string _packagesFolder; public NuGetAssemblyLoadContext(string depsJsonPath, string packagesFolder) : base(isCollectible: true) { _packagesFolder = packagesFolder; using var stream = File.OpenRead(depsJsonPath); _dependencyContext = DependencyContext.Load(stream); } protected override Assembly? Load(AssemblyName assemblyName) { // 从依赖上下文查找程序集路径 var library = _dependencyContext.RuntimeLibraries .FirstOrDefault(l => l.Name.Equals(assemblyName.Name, StringComparison.OrdinalIgnoreCase)); if (library != null) { var assemblyPath = Path.Combine(_packagesFolder, $"{library.Name}/{library.Version}", library.RuntimeAssemblyGroups.First().Assemblies.First().Path); if (File.Exists(assemblyPath)) { return LoadFromAssemblyPath(assemblyPath); } } // 回退到默认加载逻辑 return Default.LoadFromAssemblyName(assemblyName); } }加载示例
找到目标包的deps.json路径,初始化加载上下文后即可加载程序集:// 示例:加载Newtonsoft.Json的程序集 var depsPath = Path.Combine("./packages/Newtonsoft.Json/13.0.3", "Newtonsoft.Json.deps.json"); var loadContext = new NuGetAssemblyLoadContext(depsPath, "./packages"); var assembly = loadContext.LoadFromAssemblyName(new AssemblyName("Newtonsoft.Json")); // 动态调用示例 var jsonConvertType = assembly.GetType("Newtonsoft.Json.JsonConvert"); var serializeMethod = jsonConvertType.GetMethod("SerializeObject", new[] { typeof(object) }); var result = serializeMethod.Invoke(null, new object[] { new { Name = "Test" } });
内容的提问来源于stack exchange,提问作者TomSelleck

