A couple of weeks back, I wrote a post about how one could implement a custom Route which used regular expressions to define the routing. It didn't take me long though to figure out one major flaw with using regular expressions for the routes (and I bet this is why the Asp.Net MVC team didn't include them in the framework, at least not yet)...
You see, Asp.Net MVC has this great feature where it can generate an outbound url by 'reverse engineering' the routes. Let's look at an example. Assume you have a controller HomeController and an action Index on it:
public class HomeController : Controller
{
public void Index()
{
RenderView("Index");
}
}
And a route defined as follows:
routes.Add(new Route("{controller}/{action}/", new MvcRouteHandler());
Then you can use the ActionLink helper method to create a hyperlink for executing that action:
<%= this.Html.ActionLink((HomeController c) => c.Index(), "Home") %>
This will then render a hyperlink which links to "Home/Index". The benefit of doing this instead of hard coding the hyperlink, is that refactoring the names of controllers and actions won't result in broken links.
The magic that makes this work, is the GetVirtualPath method on the RouteBase class. The default Rule implementation performs some string parsing of the route pattern, and is able to construct a link using it. However, for my RegexRoute, implementing the GetVirtualPath method gets tricky - given a set of route values (the controller name, the action name and any parameters the action takes), how can we reverse engineer the regular expression pattern and build an URL? With a normal route pattern it's easy, because it is just a tokenized string with a well-defined, one-to-one match against a set of values -but a regular expression can contain wildcards, optional groups and so forth, resulting in it possibly having many valid matches for a set of values...
Thus, I can't really see a way to implement a generic algorithm that can come up with a url which matches the pattern given a set of values. Which means that basically, routes defined with regular expressions will not support outbound url generation.
A Possible Workaround
A workaround would be if you provide the code to generate that url on a route by route basis by deriving from the RegexRoute class and overriding the GetVirtualPath method. This could also be simplified by including a property on the RegexRoute class that would take a delegate that could be used to inject the GetVirutalPath implementation, so you'd get syntax looking something like this:
routes.Add(new RegexRoute("^(?<controller>.*?)//(?<action>.*?)(.aspx)?$", new MvcRouteHandler())
{
GetVirtualPath = ((route, context, dictionary) =>
new VirtualPathData(route, String.Format("{0}/{1}/", dictionary["controller"],dictionary["action"])))
});
If anyone have any better ideas, I'd love to hear about them :)