nupkg“Microsoft.Build”中的“内部 MSBuild 错误”

问题描述 投票:0回答:1

我正在尝试使用 Microsoft.Build nuget 包来:

  • 打开解决方案
  • 列举其中的项目
  • 发现创建的 DLL。

故障模式似乎非常丰富,错误消息缺乏信息,文档似乎稀缺且误导,并且示例已经过时。经过几个小时在黑暗中进行故障排除,并解决了一个又一个出现的问题,我终于发现了“内部 MSBuild 错误”,这让我进入了 Stack Overflow。

我的“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 项目组成。不过,这并不重要,因为当我指向这个简单的临时应用程序尝试解析自身时,我遇到了完全相同的失败。

问题是:为什么会失败,我必须做什么才能让它发挥作用?

c# msbuild microsoft.build microsoft.build.evaluation
1个回答
0
投票

事实证明,我之前

SolutionFile.Parse()
所做的大多数魔法咒语都是错误的。

“SolutionDir”部分是正确的,但所有其他内容都必须删除,并替换为以下神奇咒语:

  • 参考 nuget 包
    Microsoft.Build.Locator
  • 在访问任何
    MSBuild
    类型之前,以及 在单独的函数中,*1 调用
    MSBuildLocator.RegisterDefaults();

这个神奇的咒语神奇地使所有其他魔法都正确。


*1 如果您调用

RegisterDefaults()
,然后继续在同一函数中引用
MSBuild
类型,您将收到一条有趣的错误消息,幸运的是,该消息的描述性足以告诉您需要做什么修理它。神奇的东西。

© www.soinside.com 2019 - 2024. All rights reserved.