Search code examples
c#asp.net-core-webapiswashbuckle

ASP.NET Core Web API analyzer doesn't recognise ProducesResponseTypeAttribute applied as a global filter, except sometimes it does


I have an ASP.NET Core 6 Web API project. I've set three response codes as global filters:

configure.Filters.Add(new ProducesResponseTypeAttribute(StatusCodes.Status401Unauthorized));
configure.Filters.Add(new ProducesResponseTypeAttribute(StatusCodes.Status403Forbidden));
configure.Filters.Add(new ProducesResponseTypeAttribute(StatusCodes.Status500InternalServerError));

In one of my controllers, I do

return Unauthorized();

And it's being picked up by the analyzer with

API1000: Action method returns undeclared status code '401'

I thought, that's a bit annoying, but maybe it's a limitation of the analyzer that it only recognises the ProducesResponseType attribute if applied directly to a controller action.

But in a different action in the same controller, I do

return Forbid();

and that's not being flagged with the same warning.

  • Am I right in thinking that it's a limitation of the analyzer that it doesn't recognise the ProducesResponseTypeAttribute if it's applied as a global filter?
  • Why the inconsistency between Unauthorized() and Forbid()?

I don't want to disable the warning because I find it useful to remind me if I've forgotten to declare a response code, but it's annoying to have a load of false warnings dotted about.


Solution

  • About the ProducesResponseTypeAttribute only being recognized when applied on the controller action method.

    Below reply on an open issue on GitHub mentions that this is by design.

    Thanks for contacting us. The ProducesResponseType attribute is expected to be applied on actions instead. That's what the Analyzer is expecting. We don't plan to address the scenario you've brought up here.


    About Forbid() not being recognized by the analyzer while e.g. Unauthorized() and BadRequest() are.

    The ForbidResult doesn't implement IStatusCodeActionResult which is the interface that the analyzer is looking for; see the source code on GitHub:

    // Look for assignments to IStatusCodeActionResult.StatusCode
    if (TryGetStatusCode(assignmentOperation.Value, out var statusCodeValue))
    

    Instead of returning a Forbid() you might choose to return return StatusCode(StatusCodes.Status403Forbidden) which does get recognized by the analyzer when a [ProducesResponseType(StatusCodes.Status403Forbidden)] is missing on the controller action method.