I tried the solution in the accepted answer above: using the Canonicalize Pattern url strategy, and then adding a custom IRouteHandler, which then returns a custom IHttpHandler. It basically worked. Here is one warning:
With a typical default route {controller}/{action}/{id} , a controller named CatalogController and the action method inside it are as follows:
ActionResult QuickSelect(string id){ }
I noticed that the requests for "/ catalog / quick-select / 1234" worked fine, but the requests / catalog / quick -select? id = 1234 were 500'ing, because as soon as the action method was called as a result of controller.Execute() , the id parameter was null inside the action method.
I don’t know exactly why this is, but the behavior was as if MVC were not looking for the query string for the values during model binding. So, something in the implementation of ProcessRequest in the accepted answer was twisting the normal model binding process, or at least the query string value provider.
This is a transaction breaker, so I took a look at the standard MVC IHttpHandler (yay open source!): Http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/MvcHandler.cs
I will not pretend that I fully appreciated it, but obviously it does more in its implementation of ProcessRequest than what happens in the accepted answer.
So, if all we really need to do is defish the data from the incoming route data so that MVC can find our controllers / actions, why do we need to implement a whole smelly version of IHttpHandler? We do not do this! Just snatch a dash in the GetHttpHandler DashedRouteHandler method and pass the requestContext into the MvcHandler frame MvcHandler that it can do its 252 lines of magic, and your route handler should not return the second speed of IHttpHandler.
TL: dr; - Here is what I did:
public class DashedRouteHandler : IRouteHandler { public IHttpHandler GetHttpHandler(RequestContext requestContext) { requestContext.RouteData.Values["action"] = requestContext.RouteData.GetRequiredString("action").Replace("-", ""); requestContext.RouteData.Values["controller"] = requestContext.RouteData.GetRequiredString("controller").Replace("-", ""); return new MvcHandler(requestContext); } }