Skip to content

ApiVersionMatcherPolicy Invalidates valid candidates #1101

@bergmania

Description

@bergmania

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

I'm experiencing an issue where ApiVersionMatcherPolicy invalidates a valid candidate, from what looks to be an attempt to optimize performance.

The setup is quite cumbersome, but I managed to setup a minimal solution to verify it (See below).
The use case is when I have a plain old WebAPI without any versioning and I have two endpoints with the same route. Furthermore I need to have a dynamic route, to even hit this code in the ApiVersionMatcherPolicy.

When I try to call ny POST endpoint, it returns 404, because it have been invalidated by ApiVersionMatcherPolicy that finds the GET endpoint as the bestMatch. This is a problem because the ApiVersionMatcherPolicy.Order is hardcoded to be lower than HttpMethodMatcherPolicy.Order.

The issue is originally reported in Umbraco here: umbraco/Umbraco-CMS#16434

Expected Behavior

My GET endpoint is hit, like if ApiVersionMatcherPolicy is removed from the service collection.

Steps To Reproduce

I have setup a minimal setup, that shows the issue.

https://github.com/bergmania/DemoIssueWithAPIVersioning

On a new MVC project, I added a dependency

<PackageReference Include="Asp.Versioning.Mvc.ApiExplorer" Version="8.1.0" />

I added the following in program.cs

builder.Services.AddApiVersioning(x=>x.AssumeDefaultVersionWhenUnspecified = true).AddApiExplorer();
builder.Services.AddSingleton<MyDynamicControllerRoute>();

Before var app = builder.Build(); and the following afterwards

app.MapDynamicControllerRoute<MyDynamicControllerRoute>("/{**slug}");

Furtheremore I have a single file with two classes

using System.Net.Mime;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Routing;

namespace WebApplication5;

public class MyDynamicControllerRoute : DynamicRouteValueTransformer
{
    public override ValueTask<RouteValueDictionary> TransformAsync(HttpContext httpContext, RouteValueDictionary values)
    {
        return ValueTask.FromResult(values);
    }
}

[ApiController]
[Route("api/")]
public class ShowBugController : Controller
{
    [HttpPost("test")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [Consumes(MediaTypeNames.Application.Json)] // This is important because it leads to a lower (better) score when the request enter the ApiVersionMatcherPolicy, even when requested with http GET
    public IActionResult MyPost()
    {
        return Ok("OK POST");
    }

    [HttpGet("test")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    public IActionResult MyGet()
    {

        return Ok("OK GET");
    }
}

Exceptions (if any)

No response

.NET Version

8.0.303

Anything else?

No response

Metadata

Metadata

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions