在NuGet分发的自定义MSBuild任务中使用Microsoft.Win32.Registry遇运行时错误求解决
核心原因
你遇到的问题根源在于:.NET Standard 2.0版本的Microsoft.Win32.Registry.dll是转发程序集,没有实际的注册表访问实现,它依赖运行时自动绑定到对应平台(.NET Framework/.NET)的真实实现。但MSBuild任务的加载机制在这种场景下没有正确完成绑定,导致加载了空的.NET Standard程序集,触发PlatformNotSupportedException。
最佳解决方案:多目标框架构建
放弃单一的.NET Standard 2.0目标,改为同时针对MSBuild支持的具体运行时框架构建,这样每个框架的输出会直接引用对应平台的Registry实现,从根本上避免绑定问题。
步骤1:修改项目文件的目标框架
打开你的MSBuild任务项目文件(.csproj),将<TargetFramework>节点替换为多目标配置:
<TargetFrameworks>net472;net6.0</TargetFrameworks>
net472适配传统Visual Studio中的.NET Framework MSBuild环境net6.0适配dotnet build等.NET Core/.NET环境(可根据需要换成net7.0/net8.0)
步骤2:调整Registry包引用(可选)
多目标后,NuGet会自动为每个框架引用对应版本的Microsoft.Win32.Registry包:
- 对于.NET Framework目标,会自动使用系统自带的Registry实现(无需额外包,或包会自动适配)
- 对于.NET目标,会引用对应平台的包实现
如果之前的包引用有条件限制,可简化为:
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
步骤3:重新打包NuGet包
重新构建项目并打包,此时NuGet包会包含两个框架目录(net472和net6.0),每个目录下的任务程序集都会绑定到对应平台的Registry实现。MSBuild在运行时会根据自身的.NET环境自动加载匹配框架的任务程序集,不会再出现平台不支持的异常。
备选方案:调整NuGet依赖绑定(不推荐)
如果必须坚持使用.NET Standard 2.0,需要确保NuGet包正确声明Microsoft.Win32.Registry的依赖,并在打包时包含所有必要的平台实现。但这种方式依赖MSBuild的运行时绑定逻辑,稳定性不如多目标方案,具体操作:
- 在项目文件中确保
Microsoft.Win32.Registry的包引用设置为私有资产:<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0"> <PrivateAssets>all</PrivateAssets> </PackageReference> - 打包时确保NuGet包包含所有平台的
Microsoft.Win32.Registry实现程序集(可通过<IncludeAssets>配置)
但这种方式仍可能因MSBuild加载机制的差异导致绑定失败,因此优先推荐多目标方案。
内容的提问来源于stack exchange,提问作者Dark Daskin

