Skip to content

ApiVersionCollator does not filter actions for IApiBehaviorMetadata leading to actions with same controller name as api controller names getting grouped with it and leading to "Unsupported API Version" errors. #839

Closed
@rwasef1830

Description

@rwasef1830

Hello,
ApiVersionCollator groups actions by controller name and adds versioning metadata, however it fails to filter the actions list to those that are actually defined as having ApiBehavior (as defined by having IApiBehaviorMetadata which is added by [ApiController] attribute on such controllers or base classes thereof).

This leads to the side effect that if a user had 2 controllers with the same name, but different area and different namespace and different everything, one of them is an API and the other is not, accessing the non-API controller will lead to thrown errors from Endpoint routing about unsupported or unspecified API version (depending on whether ApiVersioningOptions.AssumeDefaultVersionWhenUnspecified is true or false respectively).

This behavior is very confusing and unreasonable for users with no clear way to debug or disambiguate, and there is no logging in the API collation process to troubleshoot this issue.

This kind of scenario is very common in applications such as ecommerce where there will be an API for retrieving products while at the same time an administration controller with the same name to manage such products on the store.

Note: It appears there's some filtering in another area of the library to check for this case, but this filtering is not done on the routing side which I guess is a simple oversight. Anyway, thanks for a very useful library regardless.

Here is a workaround to save others time:

class ApiBehaviorVersionCollator : ApiVersionCollator
{
    public ApiBehaviorVersionCollator(IControllerNameConvention namingConvention) : base(namingConvention)
    {
    }

    public override void OnProvidersExecuted(ActionDescriptorProviderContext context)
    {
        var newContext = new ActionDescriptorProviderContext();
        foreach (var action in context.Results)
        {
            if (!action.EndpointMetadata.OfType<IApiBehaviorMetadata>().Any())
            {
                continue;
            }

            newContext.Results.Add(action);
        }

        base.OnProvidersExecuted(newContext);
    }
}

then in the Startup sequence after calling AddApiVersioning().AddMvc(), search in the service collection for the descriptor having implementation type ApiVersionCollator and replace it with the one above.

Hope this helps someone.

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions