Я пытаюсь написать класс в .Net Core, используя компилятор Roslyn, чтобы скомпилировать мой проект и вернуть мне ClassDefinitions в этом проекте. Я собираюсь использовать эту информацию для генерации кода с помощью T4.
Это проект .Net Core 3.1.
Я не могу найти никакой хорошей документации о том, какие пакеты я должен использовать для этого.
В получателе решения после загрузки решения я не получаю документы в свойстве «Документы» и 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
'
У меня установлены эти пакеты (да, даже пробовал пререлиз):
Также пришлось установить «время выполнения» в свойстве «Исключить активы»:
Вот мой класс:
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;
}
}
}
}
И модульный тест для проверки класса:
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 ниже. Может здесь проблема?
== РЕДАКТИРОВАТЬ ==
Примечание к первому ответу: хорошо, наконец-то заработало. Пришлось скачать SDK .Net Core 3.1.404 отсюда: dotnet.microsoft.com/download/dotnet-core/thank-you/…. Добавлен путь как вы предложили, и вуаля, он начал работать.
Он отлично работает в модульном тесте, но не в шаблоне 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\16.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:
Похоже, что при установке последней версии 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 Core 3.1 с помощью .NET 5 MSBuild заканчивается ошибкой:
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
следующим образом:
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.
Оба ваших проекта .net core 3.1?
Да, все проекты 3.1
что выводит var vs = MSBuildLocator.QueryVisualStudioInstances().Aggregate(new StringBuilder(), (sb,s) => sb.AppendLine(s.MSBuildPath)).ToString();
, когда вы ставите его перед MSBuildLocator.RegisterDefaults();
?
C:\Program Files\dotnet\sdk\5.0.101\
Добавил некоторые подробности в мой вопрос
да, это поведение, которое я наблюдаю после обновления VS до последней версии. Вы пробовали RegisterMSBuildPath
, как я описал в своем обновлении?
Хорошо, заработало наконец. Пришлось скачать .Net Core 3.1.404 SDK отсюда: dotnet.microsoft.com/download/dotnet-core/thank-you/…. Добавил путь, как вы предложили, и вуаля, он начал работать. Большое спасибо за помощь.
я приведу в порядок ответ, чтобы сосредоточиться на вашей конкретной проблеме, и чуть позже обновлю репозиторий новым кодом
Теперь библиотека работает с модульным тестом, но в шаблоне она дает сбой, сообщая мне, что не может загрузить тип System.Threading.CancellationToken из, вот снова System.Runtime.
Возможная ошибка заключается в том, что QueryVisualStudioInstances() не сообщает о SDK 3.1.
это действительно странное поведение. проверьте, что показывает ваш сгенерированный шаблон QueryVisualStudioInstances
Я пришел к тому моменту, когда я собираюсь сдаться. Я просто не могу заставить это работать. На данный момент я делаю новый для провайдера, он начинает жаловаться, что не может найти System.Runtime. Без понятия, как это исправить. Отзывов о VS2019 не существует. Отладка тоже не дает подсказки.
вы видите какие-нибудь внятные сообщения из вашей библиотеки?
Отредактировал вопрос и добавил исключение
похоже, что ваш пользовательский инструмент работает под управлением .net full framework 4, поэтому мое грубое понимание процесса, когда инструмент, использующий эту старую среду выполнения, пытается вызвать roslyn в проекте, для которого требуется более новый SDK. Я недостаточно знаю среду, чтобы сделать предположение, но я бы попытался либо обновить ваш инструмент до .net core 3, либо установить этот конкретный .net 4 SDK на свой компьютер и попытаться указать там свой код.
между прочим, не рассматривали ли вы возможность замены T4, скажем, на CodeDOM?
интересно, может ли эта ТАК нить быть полезной
Да, пришло мне в голову. У меня есть библиотека из другого проекта, которую я мог бы перенести на .Net Core, которая делает именно это. Но я хотел дать Рослин шанс.
и я думаю этот ответ MS поддерживает мою идею совместимости фреймворка
Спасибо за попытку Тимур. Проект должен ссылаться на .Net Core 3.1, а не на .Net 5.0. typeof() также не решает проблему.