You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Roslyn的DiagnosticAnalyzer与CodeFixProvider中获取Workspace?

解决Roslyn分析器中获取Workspace及自动添加Logger配置到appsettings.json的问题

我之前在做Roslyn分析器的时候也踩过AdhocWorkspace的坑——它本质是一个临时的空工作区,根本不会包含你当前正在分析的项目,所以你拿到的Solution自然是空的。下面给你一步步讲怎么正确实现需求:

1. 正确获取当前分析环境的Workspace

你不需要手动创建AdhocWorkspace,应该从分析上下文里直接获取真实的Workspace。在你的DiagnosticAnalyzer类中,通过SyntaxNodeAnalysisContext或者CompilationAnalysisContext就能拿到:

public override void Initialize(AnalysisContext context)
{
    context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
    context.EnableConcurrentExecution();
    // 这里替换成你需要触发分析的语法节点,比如类声明、方法调用等
    context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.ClassDeclaration);
}

private void AnalyzeNode(SyntaxNodeAnalysisContext context)
{
    // 两种获取Workspace的方式都可以
    var workspace = context.Options.Workspace;
    // 或者从Compilation获取:var workspace = context.Compilation.Workspace;
    
    if (workspace == null) return;
    // 后续操作...
}

2. 定位项目中的appsettings.json文档

拿到Workspace后,你可以定位到当前分析项目下的appsettings.json文件:

// 获取当前正在分析的项目
var currentProject = context.Compilation.Project;
// 查找项目中的appsettings.json文档
var appsettingsDoc = currentProject.Documents
    .FirstOrDefault(d => d.Name.Equals("appsettings.json", StringComparison.OrdinalIgnoreCase));

if (appsettingsDoc == null)
{
    // 如果找不到文件,可以触发诊断提示用户
    var diagnostic = Diagnostic.Create(YourMissingFileRule, context.Node.GetLocation(), "未找到appsettings.json文件");
    context.ReportDiagnostic(diagnostic);
    return;
}

3. 检查Logger配置是否存在

读取文档文本并解析JSON,检查是否包含你需要的Logger配置:

// 获取文档内容
var text = await appsettingsDoc.GetTextAsync(context.CancellationToken);
var jsonContent = text.ToString();

// 解析JSON
using var jsonDoc = JsonDocument.Parse(jsonContent);
var hasValidLoggerConfig = false;

// 检查Logging节点及子配置
if (jsonDoc.RootElement.TryGetProperty("Logging", out var loggingElem))
{
    // 这里可以根据你的需求调整检查逻辑,比如检查LogLevel或自定义Logger节点
    hasValidLoggerConfig = loggingElem.TryGetProperty("LogLevel", out _) 
        || loggingElem.EnumerateObject().Any(p => p.Name == "YourCustomLogger");
}

// 如果没有配置,触发诊断
if (!hasValidLoggerConfig)
{
    var diagnostic = Diagnostic.Create(YourMissingConfigRule, context.Node.GetLocation(), "appsettings.json中缺少Logger配置");
    context.ReportDiagnostic(diagnostic);
}

4. 通过Code Fix自动添加配置

在你的CodeFixProvider中,修改appsettings.json的内容并生成新的解决方案:

public override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
    var diagnostic = context.Diagnostics.First();
    var currentProject = context.Document.Project;
    var appsettingsDoc = currentProject.Documents
        .FirstOrDefault(d => d.Name.Equals("appsettings.json", StringComparison.OrdinalIgnoreCase));
    
    if (appsettingsDoc == null) return;

    // 读取并解析现有JSON
    var text = await appsettingsDoc.GetTextAsync(context.CancellationToken);
    var jsonObj = JsonSerializer.Deserialize<Dictionary<string, object>>(text.ToString()) 
        ?? new Dictionary<string, object>();

    // 添加Logger配置(根据你的需求调整内容)
    if (!jsonObj.ContainsKey("Logging"))
    {
        jsonObj["Logging"] = new Dictionary<string, object>
        {
            ["LogLevel"] = new Dictionary<string, string>
            {
                ["Default"] = "Information",
                ["Microsoft.AspNetCore"] = "Warning"
            },
            ["YourCustomLogger"] = new Dictionary<string, string>
            {
                ["LogLevel"] = "Debug"
            }
        };
    }

    // 序列化回格式化后的JSON
    var updatedJson = JsonSerializer.Serialize(jsonObj, new JsonSerializerOptions { WriteIndented = true });
    var updatedText = SourceText.From(updatedJson);

    // 生成更新后的文档和解决方案
    var updatedDoc = appsettingsDoc.WithText(updatedText);
    var updatedSolution = updatedDoc.Project.Solution;

    // 注册Code Fix操作
    context.RegisterCodeFix(
        CodeAction.Create(
            title: "添加Logger配置到appsettings.json",
            createChangedSolution: _ => Task.FromResult(updatedSolution),
            equivalenceKey: nameof(AddLoggerConfigCodeFix)),
        diagnostic);
}

几个需要注意的细节

  • 异步操作:所有涉及文档读取、修改的操作都是异步的,要确保使用await处理。
  • JSON格式化:用WriteIndented = true保证修改后的JSON保持可读性。
  • 多项目场景:如果解决方案有多个项目,要确保修改的是当前分析项目的appsettings.json,避免误改其他项目的配置。
  • 错误处理:针对文件不存在、JSON格式错误等情况,要添加对应的诊断提示,提升用户体验。

内容的提问来源于stack exchange,提问作者Vijay Nirmal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:02:40