diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/AspNet/CallModelStateIsValid.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/AspNet/CallModelStateIsValid.cs index f233702e5c1..9f97417edd2 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/AspNet/CallModelStateIsValid.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/AspNet/CallModelStateIsValid.cs @@ -18,9 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; - namespace SonarAnalyzer.Rules.CSharp; [DiagnosticAnalyzer(LanguageNames.CSharp)] @@ -54,7 +51,7 @@ protected override void Initialize(SonarAnalysisContext context) => { var type = (INamedTypeSymbol)symbolStart.Symbol; if (type.DerivesFrom(KnownType.Microsoft_AspNetCore_Mvc_ControllerBase) - && !type.HasAttribute(KnownType.Microsoft_AspNetCore_Mvc_ApiControllerAttribute) + && !HasApiControllerAttribute(type) && !HasActionFilterAttribute(type)) { symbolStart.RegisterCodeBlockStartAction(ProcessCodeBlock); @@ -90,6 +87,11 @@ private static void ProcessCodeBlock(SonarCodeBlockStartAnalysisContext + type is not null + && (type.HasAttribute(KnownType.Microsoft_AspNetCore_Mvc_ApiControllerAttribute) + || HasApiControllerAttribute(type.BaseType)); + private static bool HasActionFilterAttribute(ISymbol symbol) => symbol.GetAttributes().Any(x => x.AttributeClass.DerivesFrom(KnownType.Microsoft_AspNetCore_Mvc_Filters_ActionFilterAttribute)); diff --git a/analyzers/tests/SonarAnalyzer.Test/TestCases/AspNet/CallModelStateIsValid.cs b/analyzers/tests/SonarAnalyzer.Test/TestCases/AspNet/CallModelStateIsValid.cs index 3b993e833cf..8002d829f2c 100644 --- a/analyzers/tests/SonarAnalyzer.Test/TestCases/AspNet/CallModelStateIsValid.cs +++ b/analyzers/tests/SonarAnalyzer.Test/TestCases/AspNet/CallModelStateIsValid.cs @@ -102,6 +102,15 @@ public string Add(Movie movie) // C } } +public class BaseClassHasApiControllerAttribute : ControllerWithApiAttributeAtTheClassLevel +{ + [HttpDelete("/[controller]")] + public string Remove(Movie movie) // Compliant, base class is decorated with the ApiController attribute + { + return "Hello!"; + } +} + [Controller] public class ControllerThatDoesNotInheritFromControllerBase {