using Microsoft.AspNetCore.Mvc;
using RoslynBridge.WebApi.Models;
using RoslynBridge.WebApi.Services;
namespace RoslynBridge.WebApi.Controllers;
///
/// Controller for Roslyn code analysis operations
///
[ApiController]
[Route("api/[controller]")]
[Produces("application/json")]
public class RoslynController : ControllerBase
{
private readonly IRoslynBridgeClient _bridgeClient;
private readonly ILogger _logger;
public RoslynController(IRoslynBridgeClient bridgeClient, ILogger logger)
{
_bridgeClient = bridgeClient;
_logger = logger;
}
///
/// Execute a Roslyn query
///
/// The query request
/// Optional: specific VS instance port to target
/// Cancellation token
/// The query result
/// Query executed successfully
/// Invalid request
/// Internal server error
[HttpPost("query")]
[ProducesResponseType(typeof(RoslynQueryResponse), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task> ExecuteQuery(
[FromBody] RoslynQueryRequest request,
[FromQuery] int? instancePort = null,
CancellationToken cancellationToken = default)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_logger.LogInformation("Received query request: {QueryType}", request.QueryType);
var result = await _bridgeClient.ExecuteQueryAsync(request, instancePort, cancellationToken);
if (!result.Success)
{
_logger.LogWarning("Query failed: {Error}", result.Error);
}
return Ok(result);
}
///
/// Get all projects in the solution
///
/// Optional: specific VS instance port to target
/// Cancellation token
/// List of projects
[HttpGet("projects")]
[ProducesResponseType(typeof(RoslynQueryResponse), StatusCodes.Status200OK)]
public async Task> GetProjects(
[FromQuery] int? instancePort = null,
CancellationToken cancellationToken = default)
{
var request = new RoslynQueryRequest { QueryType = "getprojects" };
var result = await _bridgeClient.ExecuteQueryAsync(request, instancePort, cancellationToken);
return Ok(result);
}
///
/// Get solution overview
///
/// Optional: specific VS instance port to target
/// Cancellation token
/// Solution statistics and overview
[HttpGet("solution/overview")]
[ProducesResponseType(typeof(RoslynQueryResponse), StatusCodes.Status200OK)]
public async Task> GetSolutionOverview(
[FromQuery] int? instancePort = null,
CancellationToken cancellationToken = default)
{
var request = new RoslynQueryRequest { QueryType = "getsolutionoverview" };
var result = await _bridgeClient.ExecuteQueryAsync(request, instancePort, cancellationToken);
return Ok(result);
}
///
/// Get diagnostics (errors and warnings)
///
/// Optional file path to filter diagnostics
/// Optional: specific VS instance port to target
/// Cancellation token
/// List of diagnostics
[HttpGet("diagnostics")]
[ProducesResponseType(typeof(RoslynQueryResponse), StatusCodes.Status200OK)]
public async Task> GetDiagnostics(
[FromQuery] string? filePath = null,
[FromQuery] int? instancePort = null,
CancellationToken cancellationToken = default)
{
var request = new RoslynQueryRequest
{
QueryType = "getdiagnostics",
FilePath = filePath
};
var result = await _bridgeClient.ExecuteQueryAsync(request, instancePort, cancellationToken);
return Ok(result);
}
///
/// Get symbol information at a specific position
///
/// File path
/// Line number (1-based)
/// Column number (0-based)
/// Optional: specific VS instance port to target
/// Cancellation token
/// Symbol information
[HttpGet("symbol")]
[ProducesResponseType(typeof(RoslynQueryResponse), StatusCodes.Status200OK)]
public async Task> GetSymbol(
[FromQuery] string filePath,
[FromQuery] int line,
[FromQuery] int column,
[FromQuery] int? instancePort = null,
CancellationToken cancellationToken = default)
{
var request = new RoslynQueryRequest
{
QueryType = "getsymbol",
FilePath = filePath,
Line = line,
Column = column
};
var result = await _bridgeClient.ExecuteQueryAsync(request, instancePort, cancellationToken);
return Ok(result);
}
///
/// Find all references to a symbol
///
/// File path
/// Line number (1-based)
/// Column number (0-based)
/// Optional: specific VS instance port to target
/// Cancellation token
/// List of references
[HttpGet("references")]
[ProducesResponseType(typeof(RoslynQueryResponse), StatusCodes.Status200OK)]
public async Task> FindReferences(
[FromQuery] string filePath,
[FromQuery] int line,
[FromQuery] int column,
[FromQuery] int? instancePort = null,
CancellationToken cancellationToken = default)
{
var request = new RoslynQueryRequest
{
QueryType = "findreferences",
FilePath = filePath,
Line = line,
Column = column
};
var result = await _bridgeClient.ExecuteQueryAsync(request, instancePort, cancellationToken);
return Ok(result);
}
///
/// Search for symbols by name
///
/// Symbol name or pattern
/// Optional symbol kind filter
/// Optional: specific VS instance port to target
/// Cancellation token
/// List of matching symbols
[HttpGet("symbol/search")]
[ProducesResponseType(typeof(RoslynQueryResponse), StatusCodes.Status200OK)]
public async Task> FindSymbol(
[FromQuery] string symbolName,
[FromQuery] string? kind = null,
[FromQuery] int? instancePort = null,
CancellationToken cancellationToken = default)
{
var request = new RoslynQueryRequest
{
QueryType = "findsymbol",
SymbolName = symbolName
};
if (!string.IsNullOrEmpty(kind))
{
request.Parameters = new Dictionary { ["kind"] = kind };
}
var result = await _bridgeClient.ExecuteQueryAsync(request, instancePort, cancellationToken);
return Ok(result);
}
///
/// Format a document
///
/// File path to format
/// Optional: specific VS instance port to target
/// Cancellation token
/// Format operation result
[HttpPost("format")]
[ProducesResponseType(typeof(RoslynQueryResponse), StatusCodes.Status200OK)]
public async Task> FormatDocument(
[FromBody] string filePath,
[FromQuery] int? instancePort = null,
CancellationToken cancellationToken = default)
{
var request = new RoslynQueryRequest
{
QueryType = "formatdocument",
FilePath = filePath
};
var result = await _bridgeClient.ExecuteQueryAsync(request, instancePort, cancellationToken);
return Ok(result);
}
///
/// Add a NuGet package to a project
///
/// Project name
/// NuGet package name
/// Optional package version
/// Optional: specific VS instance port to target
/// Cancellation token
/// Operation result
[HttpPost("project/package/add")]
[ProducesResponseType(typeof(RoslynQueryResponse), StatusCodes.Status200OK)]
public async Task> AddNuGetPackage(
[FromQuery] string projectName,
[FromQuery] string packageName,
[FromQuery] string? version = null,
[FromQuery] int? instancePort = null,
CancellationToken cancellationToken = default)
{
var request = new RoslynQueryRequest
{
QueryType = "addnugetpackage",
ProjectName = projectName,
PackageName = packageName,
Version = version
};
var result = await _bridgeClient.ExecuteQueryAsync(request, instancePort, cancellationToken);
return Ok(result);
}
///
/// Build a project
///
/// Project name
/// Build configuration (Debug/Release)
/// Optional: specific VS instance port to target
/// Cancellation token
/// Build result
[HttpPost("project/build")]
[ProducesResponseType(typeof(RoslynQueryResponse), StatusCodes.Status200OK)]
public async Task> BuildProject(
[FromQuery] string projectName,
[FromQuery] string? configuration = null,
[FromQuery] int? instancePort = null,
CancellationToken cancellationToken = default)
{
var request = new RoslynQueryRequest
{
QueryType = "buildproject",
ProjectName = projectName,
Configuration = configuration
};
var result = await _bridgeClient.ExecuteQueryAsync(request, instancePort, cancellationToken);
return Ok(result);
}
}