Odd results mixing fully-tokenized attribute-route and wildcard-map within endpoint-routing (original) (raw)

Describe the bug

The presence of the attribute-route seems to clobber requests that should go through the separate wildcard-mapped middleware. This only seems to affect fully tokenized and path-separated attribute-routes (i.e. {firstName}/{lastName}, etc.). Something like api/{firstName}/{lastName} is not affected.

My expectation using the sample below is that any request starting with /middleware would go through the middleware due to having a more-exact match based on available endpoints.

To Reproduce

using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing.Patterns; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using System.Threading.Tasks;

namespace SampleRouteConflict { public class Program { public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app
            .UseHttpsRedirection()
            .UseRouting()
            .UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();

                var appBuilder = endpoints.CreateApplicationBuilder();
                var pattern = RoutePatternFactory.Parse("/middleware");

                var pipeline = appBuilder
                    .UsePathBase(pattern.RawText)
                    .UseMiddleware<TestRouteMiddleware>()
                    .Build();

                endpoints.Map(pattern.RawText + "/{**_}", pipeline);
            });
    }
}

[ApiController]
public class TestRouteController : ControllerBase
{
    [HttpGet]
    [Route("{firstName}/{lastName}")]
    public IActionResult Index(string firstName, string lastName)
    {
        return Ok(new { firstName, lastName });
    }
}

public class TestRouteMiddleware
{
    public TestRouteMiddleware(RequestDelegate next)
    { }

    public async Task Invoke(HttpContext context)
    {
        await context.Response.WriteAsync("got to the middleware");
    }
}

}

Results

Request API Match Middleware Match 404?
/middleware X
/middleware/test X
/middleware/test1/test2 X
/bill/boga X

Results removing endpoints.MapControllers();

Request API Match Middleware Match 404?
/middleware X
/middleware/test X
/middleware/test1/test2 X
/bill/boga X

Further technical details

.NET Core SDK (reflecting any global.json):
 Version:   3.1.100
 Commit:    cd82f021f4

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.18362
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\3.1.100\

Host (useful for support):
  Version: 3.1.0
  Commit:  65f04fb6db