Forge
csharp551a3611
1using System.Text;
2using Microsoft.CodeAnalysis;
3using Microsoft.CodeAnalysis.MSBuild;
4
5namespace RoslynMcp.ServiceLayer;
6
7/// <summary>Структура solution: список проектов (имя, путь к .csproj). Только чтение, без загрузки компиляции.</summary>
8public static class GetSolutionStructure
9{
10 private static async Task<Solution?> OpenSolutionOrProjectAsync(
11 MSBuildWorkspace workspace,
12 string solutionOrProjectPath,
13 CancellationToken cancellationToken)
14 {
15 return await WorkspaceOpen.OpenSolutionOrProjectAsync(workspace, solutionOrProjectPath, cancellationToken).ConfigureAwait(false);
16 }
17
18 private static StringBuilder BuildSolutionStructureText(string solutionOrProjectPath, Solution solution, CancellationToken cancellationToken)
19 {
20 var sb = new StringBuilder();
21 sb.AppendLine("# Solution structure");
22 sb.AppendLineInvariant($"# Path: {solutionOrProjectPath}");
23 sb.AppendLine("# Projects (name, path to .csproj) — use solution_or_project_path in other tools.");
24 sb.AppendLine();
25
26 AppendProjects(sb, solution, cancellationToken);
27
28 sb.AppendLineInvariant($"Total: {solution.ProjectIds.Count} project(s).");
29 return sb;
30 }
31
32 private static void AppendProjects(StringBuilder sb, Solution solution, CancellationToken cancellationToken)
33 {
34 var index = 0;
35 foreach (var project in solution.Projects)
36 {
37 cancellationToken.ThrowIfCancellationRequested();
38 var path = project.FilePath ?? "";
39 sb.AppendLineInvariant($"{index}. {project.Name}");
40 sb.AppendLineInvariant($" {path}");
41 sb.AppendLine();
42 index++;
43 }
44 }
45
46 public static async Task<string> GetStructureAsync(
47 string solutionOrProjectPath,
48 CancellationToken cancellationToken = default)
49 {
50 if (!File.Exists(solutionOrProjectPath))
51 return $"Error: solution/project not found: {solutionOrProjectPath}";
52
53 Solution? solution = null;
54 try
55 {
56 var workspace = MSBuildWorkspace.Create(RoslynMcpWorkspaceProperties.MsBuild);
57 solution = await OpenSolutionOrProjectAsync(workspace, solutionOrProjectPath, cancellationToken).ConfigureAwait(false);
58
59 if (solution is null)
60 return "Error: failed to open solution.";
61
62 return BuildSolutionStructureText(solutionOrProjectPath, solution, cancellationToken).ToString();
63 }
64 catch (InvalidOperationException ex) when (ex.Message.Contains("slnx") || ex.Message.Contains("Slnx"))
65 {
66 return "Error: .slnx format is not supported. Use .sln or .csproj.";
67 }
68 finally
69 {
70 solution?.Workspace.Dispose();
71 }
72 }
73}
74
View only · write via MCP/CIDE