Skip to content

ApiVersionMatcherPolicy Invalidates valid candidates #1101

Open
@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

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions