Hello,
For diagnostics purposes I need to list all routes registered (with associated filters if possible) for one mvc site instance. From what I explored in source, it seems well hidden from external access.
What would be the recommanded way to do this ?
Routing in general is not a declarative system. You might be able to do this for constrained cases (ex attribute routing) but not in general. Can you tell us more about your scenario? Is this simply for debugging/diagnostics purposes?
Thanks @danroth27.
The global idea behind this is that there is multiple ways to defines routes in MVC (for the moment we do not care about the pure middlewares).
Often these route definitions are splitted in multiple places in sources, for exemple :
It can be tricky in a big website to have a _comprehensive view_ of all the route configurations. It would be usefull to quickly review all apis and pages available (and using declared filters, review that some routes require the right security policy or authorization, etc.).
This result of all registered routes would be generated at runtime, when the system has all it needs to resolve routes.
This would be some tooling to analyse the flat result of all mounded routes.
For the example above we'd like to be able to extract something like this for everything declared :
For custom routers or dynamic routes we'd be ok just to have the information that a router of type "MyCrazyRouterDependingOnCurrentWeather" is registered.
We've done this previously on our Node.js (with express) platform implementation and it was quite usefull. Here is what we had (generated by crawling the chains of middlewares at runtime) :

So, to conclude, even if _every_ routes cannot be extracted like that within MVC or if it requires some manualy post processing to achieve a view like the sample above.
We'd like to have a way to access the internal result of controllers & actions discovery (from conventions or declaratively with attributes).
I've already seen this kind of dump in mvc vnext logs (listing all routes) when no suitable route was matched but when I looked in MVC sources the dumped data was internal.
In short, there's no real 'recommended way' because routing is an imperative system. The user can always do something to circumvent diagnostic tools :laughing: The problem isn't so much that these things are hard to figure out, it's that there are a lot of them to account for, and they are fairly common in older MVC codebases.
For this reason, our ApiExplorer/Swashbuckle implementation only supports Attribute Routes. It's far easier to predict what's happening and to be precise about how things are defined. We recommend that users write APIs this way going forward. If you haven't already, take a look at https://github.com/domaindrivendev/ahoy
Here's an incomplete and imperfect sample that does something similar using a different approach: https://github.com/aspnet/Mvc/compare/route-list-sample?expand=1 I want to call our here a few things that are done/not-done and why those limitations exist.
I didn't include the verbs/filters. Those are part of the ActionDescriptor and would be trivial to add in the output.
I included actions that use attribute routing. It's trivial to know exactly what URL patterns work for those actions.
For actions that don't use attribute routing, I assume that they use conventional routing. I assume assume that the top-level route collection is the only router, and all TemplateRoute instances in the top-level collection are interesting for conventional routing.
Here's a few ways that these assumptions could go wrong:
IRouterOlder versions of MVC didn't have attribute routing, so it was common to write a route like:
routes.MapRoute("Blog/Posts/{postId}", new { controller = "Blog", action = "ReadBlogPost" });
This route really will only ever link to the BlogController#ReadBlogPost action, but my sample will list it for all of them.
An alternative approach would be to take each conventionally routed action and attempt to generate a link to it. You have data like the action/controller name from the ActionDescriptor - you'd have to generate _fake_ data like an {id} parameter. This would give you one _canonical_ URL per action, but it's only as realistic as your fake data is.
Thanks @danroth27 for theses explainations and examples.
I understand better the constrains in work here.
Most helpful comment
In short, there's no real 'recommended way' because routing is an imperative system. The user can always do something to circumvent diagnostic tools :laughing: The problem isn't so much that these things are hard to figure out, it's that there are a lot of them to account for, and they are fairly common in older MVC codebases.
For this reason, our ApiExplorer/Swashbuckle implementation only supports Attribute Routes. It's far easier to predict what's happening and to be precise about how things are defined. We recommend that users write APIs this way going forward. If you haven't already, take a look at https://github.com/domaindrivendev/ahoy
Here's an incomplete and imperfect sample that does something similar using a different approach: https://github.com/aspnet/Mvc/compare/route-list-sample?expand=1 I want to call our here a few things that are done/not-done and why those limitations exist.
I didn't include the verbs/filters. Those are part of the
ActionDescriptorand would be trivial to add in the output.I included actions that use attribute routing. It's trivial to know exactly what URL patterns work for those actions.
For actions that don't use attribute routing, I assume that they use conventional routing. I assume assume that the top-level route collection is the only router, and all
TemplateRouteinstances in the top-level collection are interesting for conventional routing.Here's a few ways that these assumptions could go wrong:
IRouterOlder versions of MVC didn't have attribute routing, so it was common to write a route like:
This route really will only ever link to the
BlogController#ReadBlogPostaction, but my sample will list it for all of them.An alternative approach would be to take each conventionally routed action and attempt to generate a link to it. You have data like the action/controller name from the
ActionDescriptor- you'd have to generate _fake_ data like an{id}parameter. This would give you one _canonical_ URL per action, but it's only as realistic as your fake data is.