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!
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.
@Anthony, if you only want to see which routes are followed with any given URL, then load the Cobisi Routing Assistant extension.
In the Visual Studio IDE, go to Tools->Extension Manager.... Then, make sure you have the Online Gallery tab selected and type "cobisi" in the search box. Once you have installed the extension, you will get a new item in the Tools menu called Cobisi (natch).
Choose the URL Mapper, unlock the project if it complains about it being locked, and then enter a URL. When you click on the Map button, you will see how the URL is routed. Super awesome if you are stuck with routing issues, IMHO.
来源:https://stackoverflow.com/questions/22416561/how-to-find-the-right-route-in-a-routecollectionroute