使用 MSBuildWorkspace 加载解决方案和项目时出现诊断错误

Diagnostic error while loading solution and projects with MSBuildWorkspace

我正在尝试使用 Roslyn 编译器在 .Net Core 中编写 class 来编译我的项目,并 return 我在该项目中的 ClassDefinitions。我将使用该信息使用 T4 生成代码。

这是一个 .Net Core 3.1 项目。

我找不到任何关于我应该使用什么包来完成这个的好的文档。

在解决方案中 getter 加载解决方案后,我在文档 属性 中找不到任何文档,并且它尝试加载的每个项目都有 1 条诊断消息:

System.ApplicationException: 'Msbuild failed when processing the file 'C:\Projects\FB-IT\grouptool\sources\Wur.Grouptool\Wur.GroupTool.Web\Wur.GroupTool.Web.csproj' with message: The SDK resolver type "WorkloadSdkResolver" failed to load. Could not load file or assembly 'System.Runtime, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.  C:\Projects\FB-IT\grouptool\sources\Wur.Grouptool\Wur.GroupTool.Web\Wur.GroupTool.Web.csproj
Msbuild failed when processing the file 'C:\Projects\FB-IT\grouptool\sources\Wur.Grouptool\Wur.GroupTool.Core\Wur.GroupTool.Core.csproj' with message: The SDK resolver type "WorkloadSdkResolver" failed to load. Could not load file or assembly 'System.Runtime, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.  C:\Projects\FB-IT\grouptool\sources\Wur.Grouptool\Wur.GroupTool.Core\Wur.GroupTool.Core.csproj
Msbuild failed when processing the file 'C:\Projects\FB-IT\grouptool\sources\Wur.Grouptool\Wur.GroupTool.Core.Tests\Wur.GroupTool.Core.Tests.csproj' with message: The SDK resolver type "WorkloadSdkResolver" failed to load. Could not load file or assembly 'System.Runtime, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.  C:\Projects\FB-IT\grouptool\sources\Wur.Grouptool\Wur.GroupTool.Core.Tests\Wur.GroupTool.Core.Tests.csproj
Msbuild failed when processing the file 'C:\Projects\FB-IT\grouptool\sources\Wur.Grouptool\Wur.Roslyn.Metadata\Wur.Roslyn.Metadata.csproj' with message: The SDK resolver type "WorkloadSdkResolver" failed to load. Could not load file or assembly 'System.Runtime, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.  C:\Projects\FB-IT\grouptool\sources\Wur.Grouptool\Wur.Roslyn.Metadata\Wur.Roslyn.Metadata.csproj
Msbuild failed when processing the file 'C:\Projects\FB-IT\grouptool\sources\Wur.Grouptool\Wur.Roslyn.Metadata.Tests\Wur.Roslyn.Metadata.Tests.csproj' with message: The SDK resolver type "WorkloadSdkResolver" failed to load. Could not load file or assembly 'System.Runtime, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.  C:\Projects\FB-IT\grouptool\sources\Wur.Grouptool\Wur.Roslyn.Metadata.Tests\Wur.Roslyn.Metadata.Tests.csproj
'

我已经安装了这些软件包(是的,甚至尝试过预发布版):

还得在'Exclude Assets'中设置'runtime' 属性:

这是我的 class:

using Microsoft.Build.Locator;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.MSBuild;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Wur.Roslyn.Metadata
{
    public class RoslynProjectProvider
    {
        public string PathToSolution { get; private set; }
        public string ProjectName { get; private set; }

        public RoslynProjectProvider(string pathToSolution, string projectName)
        {
            PathToSolution = pathToSolution;
            ProjectName = projectName;
        }

        private MSBuildWorkspace _Workspace;

        public MSBuildWorkspace Workspace
        {
            get
            {
                if (_Workspace == null)
                {
                    MSBuildLocator.RegisterDefaults();

                    _Workspace = MSBuildWorkspace.Create();
                }

                return _Workspace;
            }
        }

        private Solution _Solution;

        public Solution Solution
        {
            get
            {
                if (_Solution == null)
                {
                    _Solution = Workspace.OpenSolutionAsync(PathToSolution).Result;

                    if(Workspace.Diagnostics.Count > 0)
                    {
                        StringBuilder sb = new StringBuilder();

                        foreach (var diagnostic in Workspace.Diagnostics)
                        {
                            sb.Append(diagnostic.Message).Append(Environment.NewLine);
                        }

                        throw new ApplicationException(sb.ToString());
                    }
                }

                return _Solution;
            }
        }

        private Project _Project;

        /// <summary>
        /// Singleton Project in a solution
        /// </summary>
        public Project Project
        {
            get
            {
                if (_Project == null)
                {
                    _Project = Solution.Projects.FirstOrDefault(p => p.Name.Equals(ProjectName, StringComparison.InvariantCultureIgnoreCase));

                    if (_Project == null)
                    {
                        throw new ApplicationException($"Cannot find project {ProjectName}");
                    }
                }

                return _Project;
            }
        }

        private Compilation _Compilation;

        /// <summary>
        /// Singleton compilation of the project
        /// </summary>
        public Compilation ProjectCompilation
        {
            get
            {
                if (_Compilation == null)
                {
                    _Compilation = Project.GetCompilationAsync().Result;
                }

                return _Compilation;
            }
        }

        private List<ClassDeclarationSyntax> _Classes;

        public List<ClassDeclarationSyntax> Classes
        {
            get
            {
                if (_Classes == null)
                {
                    _Classes = new List<ClassDeclarationSyntax>();

                    foreach (var document in Project.Documents)
                    {
                        var tree = document.GetSyntaxTreeAsync().Result;

                        var semanticModel = ProjectCompilation.GetSemanticModel(tree);

                        foreach (var type in tree.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>())
                        {
                            _Classes.Add(type);
                        }
                    }
                }

                return _Classes;
            }
        }
    }
}

和单元测试来测试 class:

public class UnitTest1
{
    [Fact]
    public void Test1()
    {
        var provider = new RoslynProjectProvider(@"C:\Projects\FB-IT\grouptool\sources\Wur.Grouptool\Wur.Grouptool.sln", "Wur.GroupTool.Core");

        var classes = provider.Classes;
    }
}

== 编辑 ==

它要求版本 5.0.0.0 但 System.Runtime 的版本较低。这可能是这里的问题吗?

== 编辑 ==

Remark to first answer: Ok, got it working finally. Had to download the .Net Core 3.1.404 SDK from here: dotnet.microsoft.com/download/dotnet-core/thank-you/…. Added the path as you suggested and voila it started working.

它在单元测试中运行良好,但在 T4 模板中运行不正常。当我尝试 运行 自定义工具时,出现以下异常(启用绑定日志记录):

Severity    Code    Description Project File    Line    Suppression State
Error       Running transformation: System.IO.FileNotFoundException: Could not load file or assembly 'System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.
File name: 'System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
   at Microsoft.VisualStudio.TextTemplating9A1960153A0EC5389F1AC1A553BA062D21024CF3A0BEA5F9915226007DBBA0457E39D7A79FF10F4293C4331881904FF0454986C06541AC3156F88310BB537850.GeneratedTextTransformation.TransformText()
   at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
   at Microsoft.VisualStudio.TextTemplating.TransformationRunner.PerformTransformation()

=== Pre-bind state information ===
LOG: DisplayName = System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
 (Fully-specified)
LOG: Appbase = file:///C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/IDE/
LOG: Initial PrivatePath = NULL
Calling assembly : Wur.Roslyn.Metadata, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in LoadFrom load context.
WRN: Native image will not be probed in LoadFrom context. Native image will only be probed in default load context, like with Assembly.Load().
LOG: Using application configuration file: C:\Users\User\AppData\Local\Microsoft\VisualStudio.0_966a030a\devenv.exe.config
LOG: Using host configuration file: 
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Post-policy reference: System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/IDE/System.Runtime.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/IDE/System.Runtime/System.Runtime.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/IDE/PublicAssemblies/System.Runtime.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/IDE/PublicAssemblies/System.Runtime/System.Runtime.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/IDE/PrivateAssemblies/System.Runtime.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/IDE/PrivateAssemblies/System.Runtime/System.Runtime.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/IDE/CommonExtensions/Microsoft/TestWindow/System.Runtime.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/IDE/CommonExtensions/Microsoft/TestWindow/System.Runtime/System.Runtime.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/IDE/CommonExtensions/Platform/Debugger/System.Runtime.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/IDE/CommonExtensions/Platform/Debugger/System.Runtime/System.Runtime.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/IDE/PrivateAssemblies/DataCollectors/System.Runtime.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/IDE/PrivateAssemblies/DataCollectors/System.Runtime/System.Runtime.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/IDE/PrivateAssemblies/DataCollectors/x86/System.Runtime.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/IDE/PrivateAssemblies/DataCollectors/x86/System.Runtime/System.Runtime.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/IDE/System.Runtime.EXE.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/IDE/System.Runtime/System.Runtime.EXE.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/IDE/PublicAssemblies/System.Runtime.EXE.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/IDE/PublicAssemblies/System.Runtime/System.Runtime.EXE.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/IDE/PrivateAssemblies/System.Runtime.EXE.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/IDE/PrivateAssemblies/System.Runtime/System.Runtime.EXE.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/IDE/CommonExtensions/Microsoft/TestWindow/System.Runtime.EXE.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/IDE/CommonExtensions/Microsoft/TestWindow/System.Runtime/System.Runtime.EXE.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/IDE/CommonExtensions/Platform/Debugger/System.Runtime.EXE.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/IDE/CommonExtensions/Platform/Debugger/System.Runtime/System.Runtime.EXE.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/IDE/PrivateAssemblies/DataCollectors/System.Runtime.EXE.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/IDE/PrivateAssemblies/DataCollectors/System.Runtime/System.Runtime.EXE.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/IDE/PrivateAssemblies/DataCollectors/x86/System.Runtime.EXE.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/IDE/PrivateAssemblies/DataCollectors/x86/System.Runtime/System.Runtime.EXE.
LOG: Attempting download of new URL file:///C:/Projects/FB-IT/grouptool/sources/Wur.GroupTool/Wur.Roslyn.Metadata/bin/Debug/netcoreapp3.1/System.Runtime.DLL.
LOG: Attempting download of new URL file:///C:/Projects/FB-IT/grouptool/sources/Wur.GroupTool/Wur.Roslyn.Metadata/bin/Debug/netcoreapp3.1/System.Runtime/System.Runtime.DLL.
LOG: Attempting download of new URL file:///C:/Projects/FB-IT/grouptool/sources/Wur.GroupTool/Wur.Roslyn.Metadata/bin/Debug/netcoreapp3.1/System.Runtime.EXE.
LOG: Attempting download of new URL file:///C:/Projects/FB-IT/grouptool/sources/Wur.GroupTool/Wur.Roslyn.Metadata/bin/Debug/netcoreapp3.1/System.Runtime/System.Runtime.EXE.    Wur.GroupTool.Core.ViewModels   C:\Projects\FB-IT\grouptool\sources\Wur.GroupTool\Wur.GroupTool.Core.ViewModels\ViewModels\Web\PlayGround.tt    1

有没有可能因为它不存在而找不到它。我的目录中没有 4.2.2.0 版本:

SDK 版本不匹配

当您安装最新的 Visual Studio 时(我有 16.8.3)- MSBuildLocator 默认使用 .NET 5 MSBuild:

JsonConvert.SerializeObject(MSBuildLocator.QueryVisualStudioInstances(VisualStudioInstanceQueryOptions.Default)); 
// ouputs in VS 2019: 
// [{"Version":"5.0.101","VisualStudioRootPath":"C:\Program Files\dotnet\sdk\5.0.101\","Name":".NET Core SDK","MSBuildPath":"C:\Program Files\dotnet\sdk\5.0.101\","DiscoveryType":4}]
// just thought I'd try the same in LINQPad 5 and here's the output:
// [{"Version":{"Major":16,"Minor":8,"Build":30804,"Revision":86,"MajorRevision":0,"MinorRevision":86},"VisualStudioRootPath":"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community","Name":"Visual Studio Community 2019","MSBuildPath":"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin","DiscoveryType":2}]

当您执行 MSBuildLocator.RegisterDefaults() - 它会从上面的列表中获取 第一个 实例。

然后,使用 .NET 5 MSBuild 加载 .NET Core 3.1 项目似乎以错误告终:

Msbuild failed when processing the file '...' with message: The SDK resolver type "WorkloadSdkResolver" failed to load. Could not load file or assembly 'System.Runtime, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.

然而,您可以告诉 MSBuidLocator 在特定 SDK 位置初始化环境:MSBuildLocator.RegisterMSBuildPath。所以我尝试像这样更新你的 Workspace getter:

public MSBuildWorkspace Workspace
{
    get
    {
        if (_Workspace == null)
        {
            MSBuildLocator.RegisterMSBuildPath("C:\Program Files\dotnet\sdk\3.1.404");// your version might be different, check `dotnet --list-sdks`
            _Workspace = MSBuildWorkspace.Create();
        }
        return _Workspace;
    }
}

然后我不得不按照诊断输出并安装以下软件包:

<PackageReference Include="Microsoft.NET.HostModel" Version="3.1.6" />
<PackageReference Include="NuGet.Packaging" Version="5.8.0" />
<PackageReference Include="NuGet.ProjectModel" Version="5.8.0" />

将包安装到我的项目后 - 我能够在我的测试解决方案中成功列出 类。

还有一件事

可能让您感到困惑的是缺少对 Microsoft.CodeAnalysis.CSharp.Workspaces 的参考(有关更多背景信息,请参阅 )。

所以我最终像这样更改了你的构造函数:

public RoslynProjectProvider(string pathToSolution, string projectName)
{
    var _ = typeof(Microsoft.CodeAnalysis.CSharp.Formatting.CSharpFormattingOptions); // this line forces a reference so MSBuild loads the assembly in question.
    PathToSolution = pathToSolution;
    ProjectName = projectName;
}

如果您想查看,我已将完整的工作示例发布到 GitHub,但几乎所有代码都打包到 VS 中的 运行。