我正在尝试使用 Microsoft.Build nuget 包来:
我的“scratch”解决方案只包含一个net8.0项目,如下:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build" Version="17.9.5" />
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="17.9.5" />
</ItemGroup>
</Project>
该项目仅包含一个源文件,如下:
namespace ConsoleApp1;
using System;
using System.IO;
using System.Collections.Generic;
using Microsoft.Build.Construction;
using Microsoft.Build.Definition;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Evaluation.Context;
class Program
{
static void Main( string[] args )
{
Directory.SetCurrentDirectory( @"C:\" ); //ensure that the error we encounter further down is not due to the current directory
msBuildApiTest( @"D:\Personal\MyVisualStudioSolution\Solution.sln" ); // <-- this fails
msBuildApiTest( @"D:\Personal\scratch\scratch.sln" ); // <-- this would also fail
}
static void msBuildApiTest( string solutionFilePath )
{
string msBuildExtensionsPath = @"C:\Program Files\dotnet\sdk\8.0.102";
string msBuildSdksPath = Path.Combine( msBuildExtensionsPath, "Sdks" );
Environment.SetEnvironmentVariable( "MSBuildSDKsPath", msBuildSdksPath ); //Prevents InvalidProjectFileException: The SDK 'Microsoft.NET.Sdk' specified could not be found.
Environment.SetEnvironmentVariable( "MSBuildEnableWorkloadResolver", "false" ); //Prevents InvalidProjectFileException: The SDK 'Microsoft.NET.SDK.WorkloadAutoImportPropsLocator' specified could not be found.
ProjectOptions projectOptions = new();
projectOptions.EvaluationContext = EvaluationContext.Create( EvaluationContext.SharingPolicy.Shared );
projectOptions.LoadSettings = ProjectLoadSettings.DoNotEvaluateElementsWithFalseCondition;
projectOptions.GlobalProperties = new Dictionary<string, string>();
projectOptions.GlobalProperties.Add( "SolutionDir", Path.GetDirectoryName( solutionFilePath ) + "\\" ); //The trailing backslash is OF PARAMOUNT IMPORTANCE.
projectOptions.GlobalProperties.Add( "MSBuildExtensionsPath", msBuildExtensionsPath ); //Prevents InvalidProjectFileException: The imported project "D:\Personal\scratch\ConsoleApp1\bin\Debug\net8.0\Current\Microsoft.Common.props" was not found.
ProjectCollection projectCollection = new( ToolsetDefinitionLocations.Default );
SolutionFile solutionFile = SolutionFile.Parse( solutionFilePath );
foreach( ProjectInSolution projectInSolution in solutionFile.ProjectsInOrder )
{
if( projectInSolution.ProjectType is SolutionProjectType.SolutionFolder or SolutionProjectType.SharedProject )
continue;
Console.WriteLine( $"{projectInSolution.ProjectType}\t{projectInSolution.ProjectName}\t{projectInSolution.RelativePath}" );
Project project1 = Project.FromFile( projectInSolution.AbsolutePath, projectOptions ); // <-- this fails
Project project2 = new( projectInSolution.AbsolutePath, projectOptions.GlobalProperties, "Current", projectCollection ); // <-- this would also fail
}
}
}
最后两条语句均失败。
例外是
Microsoft.Build.Exceptions.InvalidProjectFileException
。
异常信息如下:
The expression "[MSBuild]::GetTargetFrameworkIdentifier(net8.0)" cannot be evaluated.
MSB0001: Internal MSBuild Error: A required NuGet assembly was not found.
Expected Path: D:\Personal\scratch\ConsoleApp1\bin\Debug\net8.0
C:\Program Files\dotnet\sdk\8.0.102\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.TargetFrameworkInference.targets
备注:
“预期路径”(无论这意味着什么)指向我的临时解决方案的输出目录,这没有任何意义,因为这不是我要解析的解决方案,并且我没有向 Microsoft.Build 提供任何路径我的暂存解决方案。事实上,我什至将当前目录切换到
C:\
以确保错误不是由此引起的。
@"C:\Program Files\dotnet\sdk\8.0.102"
路径适用于我的机器,您可能需要为您的机器更改它。自动发现固然很好,但这超出了这个临时应用程序的范围。
“D:\Personal\MyVisualStudioSolution\Solution.sln”处的解决方案是我正在尝试解析的解决方案,由许多 net8.0 C# 项目和一个 net472 项目组成。不过,这并不重要,因为当我指向这个简单的临时应用程序尝试解析自身时,我遇到了完全相同的失败。
问题是:为什么会失败,我必须做什么才能让它发挥作用?
事实证明,我之前
SolutionFile.Parse()
所做的大多数魔法咒语都是错误的。
“SolutionDir”部分是正确的,但所有其他内容都必须删除,并替换为以下神奇咒语:
Microsoft.Build.Locator
MSBuild
类型之前,以及 在单独的函数中,*1 调用 MSBuildLocator.RegisterDefaults();
这个神奇的咒语神奇地使所有其他魔法都正确。
*1 如果您调用
RegisterDefaults()
,然后继续在同一函数中引用 MSBuild
类型,您将收到一条有趣的错误消息,幸运的是,该消息的描述性足以告诉您需要做什么修理它。神奇的东西。