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();
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:
/search?query=term
/api/search?query=term
/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.
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.