我有一个使用此命令的自定义msbuild任务:
var workspace = Workspace.LoadStandAloneProject(csprojPath);
当我运行它时,它会抛出以下错误:
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) ...
在控制台应用程序中使用相同项目运行时,相同的代码运行正常。
有什么想法吗?谷歌搜索没有帮助!
答案 0 :(得分:4)
以下是Roslyn的MsBuild任务示例。
为了重建Workspace.LoadProjectFromCommandLineArguments方法所需的命令行,我们必须将msbuild文件中的一些信息传递给我们的任务。
这就是Roslyn需要解析源文件的全部内容。 (参见本文末尾的注释。)
所以创建一个C#类库项目。 这些是您需要的项目参考:
Microsoft.Build.Framework
Microsoft.Build.Utilities.v4.0
Roslyn.Compilers
Roslyn.Services
自定义MsBuild任务的代码:
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文件的末尾添加以下行(就在关闭Project标记之前)。但是,只有项目已经成功构建并且它可以在输出文件夹中找到您的任务dll。
<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文件的源转储到构建输出。
请注意,其他csc.exe开关(如ConditionalDirectives,输出类型等)可能也很重要,具体取决于您尝试执行的分析类型。您也可以使用此模式将它们传递给您的任务。有关MsBuild传递给csc.exe的完整属性列表,请参阅$(MSBuildToolsPath)\ Microsoft.CSharp.targets文件,CoreCompile目标,Csc任务。
答案 1 :(得分:-1)
这是MSBuild的限制。 Roslyn无法在构建期间递归调用MSBuild以确定项目属性/文件/引用。要在构建任务期间创建Roslyn IProject
,请尝试使用LoadFromCommandLineArgs()
方法。您需要构造您的任务以获取与CscTask最终传递给编译器相同的参数。
希望这有帮助!