Is there an easy way to get the MvcRouteHandler to convert all hyphens in the action and controller sections of an incoming URL to underscores as hyphens are not supported in method or class names.
This would be so that I could support such structures as sample.com/test-page/edit-details mapping to Action edit_details and Controller test_pagecontroller while continuing to use MapRoute method.
I understand I can specify an action name attribute and support hyphens in controller names which out manually adding routes to achieve this however I am looking for an automated way so save errors when adding new controllers and actions.
C# version of John's Post for anyone who would prefer it: C# and VB version on my blog
public class HyphenatedRouteHandler : MvcRouteHandler{
protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
{
requestContext.RouteData.Values["controller"] = requestContext.RouteData.Values["controller"].ToString().Replace("-", "_");
requestContext.RouteData.Values["action"] = requestContext.RouteData.Values["action"].ToString().Replace("-", "_");
return base.GetHttpHandler(requestContext);
}
}
...and the new route:
routes.Add(
new Route("{controller}/{action}/{id}",
new RouteValueDictionary(
new { controller = "Default", action = "Index", id = "" }),
new HyphenatedRouteHandler())
);
You can use the following method too but bear in mind you would need to name the view My-Action which can be annoying if you like letting visual studio auto generate your view files.
[ActionName("My-Action")]
public ActionResult MyAction() {
return View();
}
I have worked out a solution. The requestContext inside the MvcRouteHandler contains the values for the controller and action on which you can do a simple replace on.
Public Class HyphenatedRouteHandler
Inherits MvcRouteHandler
Protected Overrides Function GetHttpHandler(ByVal requestContext As System.Web.Routing.RequestContext) As System.Web.IHttpHandler
requestContext.RouteData.Values("controller") = requestContext.RouteData.Values("controller").ToString.Replace("-", "_")
requestContext.RouteData.Values("action") = requestContext.RouteData.Values("action").ToString.Replace("-", "_")
Return MyBase.GetHttpHandler(requestContext)
End Function
End Class
Then all you need to replace the routes.MapRoute with an equivalent routes.Add specifying the the new route handler. This is required as the MapRoute does not allow you to specify a custom route handler.
routes.Add(New Route("{controller}/{action}/{id}", New RouteValueDictionary(New With {.controller = "Home", .action = "Index", .id = ""}), New HyphenatedRouteHandler()))
All you really need to do in this case is name your views with the hyphens as you want it to appear in the URL, remove the hyphens in your controller and then add an ActionName attribute that has the hyphens back in it. There's no need to have underscores at all.
Have a view called edit-details.aspx
And have a controller like this:
[ActionName("edit-details")]
public ActionResult EditDetails(int id)
{
// your code
}
I realize this is quite an old question, but to me this is only half the story of accepting url's with hyphens in them, the other half is generating these urls while still being able to use Html.ActionLink and other helpers in the MVC framework, I solved this by creating a custom route class similar, here is the code in case it helps anyone coming here from a google search. It also includes the lower casing of the url too.
public class SeoFriendlyRoute : Route
{
// constructor overrides from Route go here, there is 4 of them
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
var path = base.GetVirtualPath(requestContext, values);
if (path != null)
{
var indexes = new List<int>();
var charArray = path.VirtualPath.Split('?')[0].ToCharArray();
for (int index = 0; index < charArray.Length; index++)
{
var c = charArray[index];
if (index > 0 && char.IsUpper(c) && charArray[index - 1] != '/')
indexes.Add(index);
}
indexes.Reverse();
indexes.Remove(0);
foreach (var index in indexes)
path.VirtualPath = path.VirtualPath.Insert(index, "-");
path.VirtualPath = path.VirtualPath.ToLowerInvariant();
}
return path;
}
}
then when adding routes, you can either create a RouteCollection extensions or just use the following in your global routing declarations
routes.Add(
new SeoFriendlyRoute("{controller}/{action}/{id}",
new RouteValueDictionary(
new { controller = "Default", action = "Index", id = "" }),
new HyphenatedRouteHandler())
);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With