Search code examples
c#asp.net-coreroutes.net-8.0minimal-apis

app.MapDynamicControllerRoute<Router>("{**path}") doesn't seem to affect routing


Edit:

The problem was that app.UseRouting(); was called before app.Use(async (context, next) => {...}). Once I place everything in this order, it worked:

app.Use(async (context, next) { ... });
app.UseRouting();
app.MapControllers();

Original Post:

I'm running a .net 8.0 asp.net minimal API app that is being deployed in various locations, each with different preceding request URL. For instance my search controller:

[ApiController]
[Route("[controller]")]
public class SearchController : ControllerBase {
    [HttpGet] public async Task<ActionResult<SomeValue[]>> Search([FromQuery] string query) { ... }
}

Can be triggered with any of these exemplary strings:

  1. /search?query=term
  2. /api/search?query=term
  3. /some/multi/part/prefix/search?query=term

I tried to find a way to consider only the last part, like [Route([*/controller])], but there's no way to accomplish it using the Route attribute, unfortunately.

So I tried to do some dynamic request manipulations, such as:

app.Use(async (context, next) => {
    context.Request.Path = "/search";
    var request = context.Request.Path.Value;
    var i = request.LastIndexOf('/');
    context.Request.Path = request[..i];
    await next();
});

But albeit witnessing the context.Request.Path indeed changing, the routing itself didn't seem to be affected by it.

So I tried app.MapDynamicControllerRoute<Router>("{**path}") and forced (for the sake of testing):

public class Router : DynamicRouteValueTransformer {
    public override ValueTask<RouteValueDictionary> TransformAsync(HttpContext httpContext, RouteValueDictionary values) {
        httpContext.Request.Path = "/search";
        values["path"] = "search";
        return new(values);
    }
}

And again: httpContext.Request.Path and values["path"] did both reflect the change, but the actual routing hasn't changed, and the controller hasn't been hit.

So what am I missing? any way to accomplish this dynamic routing?

I found no exact match for my case with actual working solution, and couldn't make app.MapDynamicControllerRoute<Router>("{**path}") change actual routing.


Solution

  • You could try explicit add app.UseRouting(); after the middleware.

    var app = builder.Build();
    app.Use(async (context, next) => {
       //if the path contains "search", then change it all to "search"
        if (context.Request.Path.Value.Contains("/search"))
        {
            context.Request.Path = "/search";
        } 
        await next();
    });
    app.UseRouting();
    ...
    

    From my experience, if you don't use "app.useRouting()" . Asp.net core will automatically use it at the beginning of middleware pipeline. But when you manually use it, you are forcing a pipeline order to use it.
    enter image description here