罗斯林:工作区载荷控制台应用程序而不是在MSBuild任务 [英] Roslyn: workspace loads in console application but not in msbuild task

查看:217
本文介绍了罗斯林:工作区载荷控制台应用程序而不是在MSBuild任务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这个命令的自定义MSBuild任务:

I have a custom msbuild task with this command:

var workspace = Workspace.LoadStandAloneProject(csprojPath);

当我运行它,它引发以下错误:

When I run it, it throws the following error:


  System.InvalidCastException was unhandled by user code
  Message=Unable to cast transparent proxy to type 'Roslyn.Utilities.SerializableDataStorage'.
  Source=Roslyn.Services
  StackTrace:
       at Roslyn.Utilities.RemoteServices.CreateInstance[T]()
       at Roslyn.Services.Host.TemporaryStorageServiceFactory.CreateService(IWorkspaceServiceProvider workspaceServices)
       at Roslyn.Services.Host.WorkspaceServiceProviderFactory.Provider.c__DisplayClass7.b__4()
       at Roslyn.Utilities.NonReentrantLazy`1.get_Value()
       at Roslyn.Services.Host.WorkspaceServiceProviderFactory.Provider.GetService[TWorkspaceService]()
       at Roslyn.Services.SolutionServices..ctor(IWorkspaceServiceProvider workspaceServices, ILanguageServiceProviderFactory languageServicesFactory)
       at Roslyn.Services.Solution..ctor(SolutionId id, String filePath, VersionStamp version, VersionStamp latestProjectVersion, ILanguageServiceProviderFactory languageServiceProviderFactory, IWorkspaceServiceProvider workspaceServices)
       at Roslyn.Services.Host.SolutionFactoryServiceFactory.SolutionFactoryService.CreateSolution(SolutionId id)
       at Roslyn.Services.Host.TrackingWorkspace.CreateNewSolution(ISolutionFactoryService solutionFactory, SolutionId id)
       at Roslyn.Services.Host.TrackingWorkspace..ctor(IWorkspaceServiceProvider workspaceServiceProvider, Boolean enableBackgroundCompilation, Boolean enableInProgressSolutions)
       at Roslyn.Services.Host.HostWorkspace..ctor(IWorkspaceServiceProvider workspaceServiceProvider, Boolean enableBackgroundCompilation, Boolean enableInProgressSolutions, Boolean enableFileTracking)
       at Roslyn.Services.Host.LoadedWorkspace..ctor(ILanguageServiceProviderFactory languageServiceProviderFactory, IWorkspaceServiceProvider workspaceServiceProvider, IProjectFileService projectFileFactsService, IDictionary`2 globalProperties, Boolean enableBackgroundCompilation, Boolean enableFileTracking)
       at Roslyn.Services.Host.LoadedWorkspace..ctor(ExportProvider exportProvider, Boolean solutionLoadOnly, Boolean enableFileTracking)
       at Roslyn.Services.Host.LoadedWorkspace..ctor(Boolean enableFileTracking)
       at Roslyn.Services.Host.LoadedWorkspace.LoadStandAloneProject(String projectFileName, String configuration, String platform, String language, Boolean enableFileTracking)
       at Roslyn.Services.Workspace.LoadStandAloneProject(String projectFileName, String configuration, String platform, String language, Boolean enableFileTracking)
       ...

同样的code,当一个控制台应用程序运行,同一个项目,运行良好。

The same code, when run in a console application, with the same project, runs fine.

任何想法?谷歌搜索没有帮助!

Any ideas? Googling has not been helpful!

推荐答案

下面是一个示例MSBuild任务与罗斯林。

Here's a sample MsBuild task with Roslyn.

为了重建被Workspace.LoadProjectFromCommandLineArguments方法需要在命令行中,我们要通过从文件的MSBuild一些信息进入我们的任务。

In order to reconstruct the command line needed by the Workspace.LoadProjectFromCommandLineArguments method, we have to pass some info from the msbuild file into our task.


  • 引用的装置:
    @(ReferencePath)项目组。

  • 要编译
  • 在CS文件:在@(编译)项目组

  • 的基本目录:$的(MSBuildProjectDirectory)内置属性

这是所有罗斯林需要分析你的源文件。 (见注在这篇文章的末尾。)

That's all that Roslyn needs to parse your source files. (See the note at the end of this post.)

因此​​,创建一个C#类库项目。
这些都是项目引用,你需要:

So create a C# class library project. These are the project references that you'll need:

Microsoft.Build.Framework
Microsoft.Build.Utilities.v4.0
Roslyn.Compilers
Roslyn.Services

在code自定义MSBuild任务:

The code for the custom MsBuild task:

using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Roslyn.Services;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace RoslynMsBuildTask
{
    public class RoslynTask : Task
    {
        [Required]
        public ITaskItem[] ReferencePath { get; set; }

        [Required]
        public ITaskItem[] Compile { get; set; }

        [Required]
        public ITaskItem BaseDirectory { get; set; }

        public override bool Execute()
        {
            Log.LogMessage(MessageImportance.High, "RoslynTask.Execute called...\n");

            // Format the command line with the minimal info needed for Roslyn to create a workspace.
            var commandLineForProject = string.Format("/reference:{0} {1}",
                ReferencePath.Select(i => i.ItemSpec).ToSingleString(",", "\"", "\""),
                Compile.Select(i => i.ItemSpec).ToSingleString(" ", "\"", "\""));

            // Create the Roslyn workspace.
            var workspace = Workspace.LoadProjectFromCommandLineArguments("MyProject", "C#", commandLineForProject, BaseDirectory.ItemSpec);

            // Make sure that Roslyn actually parsed the project: dump the source from a syntax tree to the build log.
            Log.LogMessage(MessageImportance.High, workspace.CurrentSolution.Projects.First()
                .Documents.First(i => i.FilePath.EndsWith(".cs")).GetSyntaxRoot().GetText().ToString());

            return true;
        }
    }

    public static class IEnumerableExtension
    {
        public static string ToSingleString<T>(this IEnumerable<T> collection, string separator, string leftWrapper, string rightWrapper)
        {
            var stringBuilder = new StringBuilder();

            foreach (var item in collection)
            {
                if (stringBuilder.Length > 0)
                {
                    if (!string.IsNullOrEmpty(separator))
                        stringBuilder.Append(separator);
                }

                if (!string.IsNullOrEmpty(leftWrapper))
                    stringBuilder.Append(leftWrapper);

                stringBuilder.Append(item.ToString());

                if (!string.IsNullOrEmpty(rightWrapper))
                    stringBuilder.Append(rightWrapper);
            }

            return stringBuilder.ToString();
        }
    }
}

要证明它的实际工作,在你的csproj文件的末尾添加以下行(在结束标记项目之前)。但是,只有当该项目已成功构建,它可以在输出文件夹你的任务DLL。

To demonstrate that it actually works, add the following lines at the end of your csproj file (just before the closing Project tag). But only if the project was already built successfully and it can find your task dll in the output folder.

  <Target Name="AfterBuild" DependsOnTargets="RoslynTask"/>
  <UsingTask AssemblyFile="$(OutputPath)\RoslynMsBuildTask.dll" TaskName="RoslynMsBuildTask.RoslynTask" />
  <Target Name="RoslynTask">
    <RoslynTask ReferencePath="@(ReferencePath)" Compile="@(Compile)" BaseDirectory="$(MSBuildProjectDirectory)" />
  </Target>

将倾倒在你的第一个CS文件的源生成输出。

It will dump the source of your first cs file to the build output.

请注意,其他CSC.EXE交换机(如ConditionalDirectives,输出类型等),也可能事情取决于分析你正在尝试做的类型。您也可以将它们使用这种模式传递给你的任务。见$(MSBuildToolsPath)\\ Microsoft.CSharp.targets文件,CoreCompile目标,CSC任务为的MSBuild传递给CSC.EXE属性的完整列表。

Note that other csc.exe switches (like ConditionalDirectives, output type, etc) may also matter depending on the type of analysis you are trying to do. You can also pass them to your task using this pattern. See $(MSBuildToolsPath)\Microsoft.CSharp.targets file, CoreCompile target, Csc task for a complete list of properties that MsBuild passes to csc.exe.

这篇关于罗斯林:工作区载荷控制台应用程序而不是在MSBuild任务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆