创建MSBuild API的Project对象失败:NuGet SDK解析引发异常
问题解决:MSBuild项目加载时System.Text.Json MissingMethodException异常
问题概述
- 场景:基于.NET Framework开发的项目分析工具,加载使用
MSBuild.SDK.SystemWeb/4.0.104的SDK风格.NET Framework项目 - 异常表现:调用
new Microsoft.Build.Evaluation.Project(projectFilePath)时抛出Microsoft.Build.Exceptions.InvalidProjectFileException,根源为TypeInitializationException,内部嵌套MissingMethodException:找不到Void System.Text.Json.JsonSerializerOptions.set_Encoder(System.Text.Encodings.Web.JavaScriptEncoder)方法 - 矛盾点:自行在Main函数中测试设置
JsonSerializerOptions.Encoder属性正常,运行时加载的System.Text.Json.dll为9.x版本,ILSpy确认该属性存在setter;手动添加程序集绑定重定向无效,仅执行dotnet restore完成SDK还原后工具才能正常工作
根因分析
异常核心是NuGet.Packaging组件在静态初始化阶段,加载的System.Text.Json版本与工具运行时实际加载的版本存在隐性上下文不兼容:
NuGet.Packaging.NupkgMetadataFileFormat的静态构造函数会初始化JsonSerializerOptions并设置Encoder属性,但该组件依赖的System.Text.Json版本,与工具引用的9.x版本存在加载上下文差异dotnet restore操作会在项目目录下生成正确的NuGet包缓存及绑定重定向配置(如obj\project.assets.json),这些配置会修正MSBuild加载组件时的程序集版本匹配问题,而手动添加的绑定重定向未覆盖MSBuild组件的加载上下文
解决方案
1. 强制工具启动时触发NuGet缓存初始化
在创建Project对象之前,执行NuGet相关初始化逻辑,确保正确加载所需的System.Text.Json版本:
using NuGet.Common; using NuGet.Configuration; using NuGet.Packaging; // 初始化NuGet配置与包缓存 var settings = Settings.LoadDefaultSettings(null); var packageSourceProvider = new PackageSourceProvider(settings); var sourceRepositoryProvider = new SourceRepositoryProvider(packageSourceProvider, Repository.Provider.GetCoreV3()); // 触发NuGet组件加载,确保程序集版本匹配 _ = sourceRepositoryProvider.GetRepositories();
2. 配置工具项目的MSBuild属性,对齐依赖版本
在工具的.csproj文件中添加以下配置,强制NuGet.Packaging和System.Text.Json的版本与MSBuild组件兼容:
<PropertyGroup> <!-- 强制使用与MSBuild兼容的NuGet.Packaging版本 --> <NuGetPackagingVersion>6.7.0</NuGetPackagingVersion> </PropertyGroup> <ItemGroup> <PackageReference Include="NuGet.Packaging" Version="$(NuGetPackagingVersion)" /> <PackageReference Include="System.Text.Json" Version="9.0.0" /> <!-- 确保绑定重定向自动生成 --> <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> <GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType> </ItemGroup>
3. 工具启动前自动执行dotnet restore(可选)
如果工具需要处理未执行过restore的项目,可在加载Project之前调用dotnet restore命令自动完成缓存初始化:
using System.Diagnostics; var process = new ProcessStartInfo { FileName = "dotnet", Arguments = $"restore \"{projectFilePath}\"", UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true }; using var dotnetProcess = Process.Start(process); dotnetProcess.WaitForExit(); // 检查退出码确保restore成功 if (dotnetProcess.ExitCode != 0) { var error = dotnetProcess.StandardError.ReadToEnd(); throw new InvalidOperationException($"dotnet restore failed: {error}"); }
关键说明
- .NET Framework下的MSBuild组件加载上下文与普通应用程序不同,手动添加的绑定重定向可能无法覆盖MSBuild内部加载的NuGet组件
dotnet restore不仅会下载包,还会生成针对当前项目的程序集绑定配置,这些配置会被MSBuild自动读取,从而解决版本不匹配问题
内容的提问来源于stack exchange,提问作者mark
相关产品推荐
相关产品推荐

