Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find the right route in a RouteCollectionRoute?

I am testing ASP MVC routes. I am having an issue with attribute routes in ASP MVC 5.1

When I have a controller like this:

public class FooController : Controller
{
    [Route("foo")]
    [HttpGet]
    public ActionResult Get()
    {
      .... 
    }

    [Route("foo")]
    [HttpPost]
    public ActionResult Post()
    {
      .... 
    }
}

Then in order to test which route matches a particular request, I call routes.GetRouteData. I get a System.Web.Routing.RouteData that contains the route as well as values that should say which controller and action are matched.

The problem is that this route is now an instance of RouteCollectionRoute this internal class is a wrapper over a group of routes to these two actions. The controller is in the RouteData.values, but the action is not. You can get as these contained routes with routeData.Values["MS_DirectRouteMatches"] as IList<RouteData>.

In the example given, there will be two routes in the list, for the two action methods. I need to know which of the contained routes is actually matched, so that I can read off what the matched route's action method name is. How do I resolve this route?

I'm a bit puzzled by the design choice of having a RouteCollectionRoute at all. When routing, you have a route collection, then you resolve the route for a url by calling GetRouteData. Now you have one route. But if it's a RouteCollectionRoute so it's still a collection of routes and route resolution isn't over yet. What's been gained by having a RouteCollectionRoute? Is route resolution now a two-step process? Or a recursive process?

I know I am trawling through the internals of ASP MVC, but it's the only way as it really wasn't designed with this kind of testability in mind. Even simple things like exposing some internal classes or methods would have helped a lot!

like image 978
Anthony Avatar asked Mar 14 '14 22:03

Anthony


1 Answers

Attribute routing is a bit trickier in ASP.NET MVC than traditional convention based. You can start review from System.Web.Mvc.Controller.ExecuteCore() where GetActionName() returns null for attribute routing and let action selector choose which action to execute. Then you can jump to System.Web.Mvc.ControllerActionInvoker.FindAction() that does all magic and finds RouteCandidates then filters them by ActionNameSelectors, ActionSelectors etc.

I've made a pull request with implementation that wraps ASP.NET MVC logic.

One important thing to add: The implementation is quite heavy with a lot of reflection. Please take a look at how the ASP.NET team tests routing e.g. in AttributeRoutingTest.cs. You can use you own ControllerFactory that will return mocked controller with actions returning their names, parameters, etc. This would be much easier in my opinion.

like image 141
Alexandr Nikitin Avatar answered Oct 02 '22 15:10

Alexandr Nikitin