如何用Roslyn代码分析器检测Web API控制器方法缺失的Custom属性
解决方案:检测Web API控制器方法缺失Custom属性的Roslyn分析器
一、完善分析器核心判断逻辑
需要在AnalyzeNode方法中完成两个关键校验:确认方法属于Web API控制器类、检查方法是否已标记Custom属性。修改后的完整代码如下:
private void AnalyzeNode(SyntaxNodeAnalysisContext context) { var methodDeclaration = (MethodDeclarationSyntax)context.Node; // 获取方法的语义符号,用于后续类型和属性的语义校验 var methodSymbol = context.SemanticModel.GetDeclaredSymbol(methodDeclaration, context.CancellationToken); if (methodSymbol == null) return; // 判断方法所在类是否为Web API控制器(兼容ASP.NET Core的ControllerBase和传统Web API的ApiController) var containingType = methodSymbol.ContainingType; var isApiController = containingType.AllInterfaces.Any(i => i.Name == "IApiController") || containingType.BaseType?.Name is "ControllerBase" or "ApiController"; if (!isApiController) return; // 检查方法是否已包含Custom属性(用语义分析兼容属性别名、全名称写法) var hasCustomAttribute = methodSymbol.GetAttributes().Any(attr => attr.AttributeClass?.Name is "CustomAttribute" or "Custom"); if (hasCustomAttribute) return; // 触发诊断提示 var diagnostic = Diagnostic.Create( Rule, // 提前定义的DiagnosticRule实例 methodDeclaration.Identifier.GetLocation(), methodDeclaration.Identifier.Text); context.ReportDiagnostic(diagnostic); }
二、实现代码修复提供者
为缺失属性的方法自动添加[Custom]的代码修复逻辑:
public sealed class CustomAttributeCodeFixProvider : CodeFixProvider { public override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(YourAnalyzer.DiagnosticId); // 对应分析器的诊断ID public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; public override async Task RegisterCodeFixesAsync(CodeFixContext context) { var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; // 定位到目标方法声明节点 var methodDeclaration = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf() .OfType<MethodDeclarationSyntax>().First(); // 注册修复动作 context.RegisterCodeFix( CodeAction.Create( title: "添加Custom属性", createChangedDocument: c => AddCustomAttributeAsync(context.Document, methodDeclaration, c), equivalenceKey: "AddCustomAttribute"), diagnostic); } private async Task<Document> AddCustomAttributeAsync( Document document, MethodDeclarationSyntax methodDeclaration, CancellationToken cancellationToken) { // 创建Custom属性语法节点 var customAttribute = SyntaxFactory.Attribute( SyntaxFactory.IdentifierName("Custom")) .WithArgumentList(SyntaxFactory.AttributeArgumentList()); // 将属性添加到方法的属性列表(无属性列表则新建) var newMethodDeclaration = methodDeclaration.AttributeLists.Any() ? methodDeclaration.WithAttributeLists( methodDeclaration.AttributeLists.Insert(0, SyntaxFactory.AttributeList(SyntaxFactory.SingletonSeparatedList(customAttribute)))) : methodDeclaration.WithAttributeLists( SyntaxFactory.SingletonList(SyntaxFactory.AttributeList( SyntaxFactory.SingletonSeparatedList(customAttribute)))); // 更新语法树并返回新文档 var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var newRoot = root.ReplaceNode(methodDeclaration, newMethodDeclaration); return document.WithSyntaxRoot(newRoot); } }
关键补充说明
- 语义分析优先:用符号校验替代纯语法检查,能兼容
using Custom = MyNamespace.MyCustomAttribute别名、属性全名称等场景 - 诊断规则定义:需提前创建
DiagnosticRule实例,示例如下:public static readonly DiagnosticRule Rule = new DiagnosticRule( id: "MY001", title: "Web API方法缺失Custom属性", messageFormat: "方法 '{0}' 缺少Custom属性", category: "Usage", defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: true);
内容的提问来源于stack exchange,提问作者Danish
相关产品推荐
相关产品推荐

