受欢迎的博客标签

Find out if a URL matches an action in ASP.NET MVC Core

Published

You might have faced a scenario where you have a URL, and you need to find out if it maps to an action in your MVC Core app.

Turns out it's not that difficult, we will just have to leverage some framework classes. Define the route and method to test

First we need to define the URL and HTTP method for the request:

string url = "/Home/Index";

string method = "GET";

Find the IRouteCollection router

The router is key to matching a URL to a controller action. In this case, we need the IRouteCollection.

In a controller, we can find it like so:

IRouteCollection router = RouteData.Routers.OfType<IRouteCollection>().First();

Now, we'll need to create an HttpContext so we can give the router something to test. We can do it by injecting IHttpContextFactory into our controller:

private readonly IHttpContextFactory _httpContextFactory;

public HomeController( IHttpContextFactory httpContextFactory)

{

_httpContextFactory = httpContextFactory;

}

And then creating the context with appropriate values:

//Also pass the feature collection of the existing context

HttpContext context = _httpContextFactory.Create(HttpContext.Features);

context.Request.Path = "/Home/Index";

context.Request.Method = "GET";

Now we can check if the route exists:

//Create RouteContext from HttpContext

var routeContext = new RouteContext(context);

//Run it through the router

await router.RouteAsync(routeContext);

//If router assigned a handler, URL matches an action

bool exists = routeContext.Handler != null;

If the router assigned a handler for the call, then a match was found! This means there is an action that would match if a request with that URL and HTTP method was received.

Here is the example as a whole:

public class HomeController : Controller

{

private readonly IHttpContextFactory _httpContextFactory;

public HomeController( IHttpContextFactory httpContextFactory)

{

_httpContextFactory = httpContextFactory;

}

public async Task<IActionResult> Index()

{

IRouteCollection router = RouteData.Routers.OfType<IRouteCollection>().First();

HttpContext context = _httpContextFactory.Create(HttpContext.Features);

context.Request.Path = "/Home/TestPostAction";

context.Request.Method = "POST";

var routeContext = new RouteContext(context);

await router.RouteAsync(routeContext);

bool exists = routeContext.Handler != null; return View();

}

[HttpPost]

public IActionResult TestPostAction()

{

return Ok();

}

}

This works for attribute routing as well. Default values are also taken into consideration, so "/", "/Home", and "/Home/Index" all work, given the default route template. It will not match an action if: The HTTP method is wrong An inline route constraint is not satisfied (e.g. [HttpGet("{id:int}")]) .