How can I implement "natural" url scheme routing tables in ASP.NET MVC

910 views Asked by At

I would like to specify my routing tables such that they would feel much more "natural"

/Products
/Product/17
/Product/Edit/17
/Product/Create

Close to the defaults configuration but such that "Index" action would be mapped to the multiples form of the controller name and "Details" action would be mapped directly with an id of the item directly following the controller name.

I know I can achieve this by explicitly defining special routing mappings like this:

routes.MapRoute(
    "ProductsList",
    "Products",
    new { controller = "Product", action = "Index" }
);
routes.MapRoute(
    "ProductDetails",
    "Product/{id}",
    new { controller = "Product", action = "Details" }
);

/*
 * Ditto for all other controllers
 */

routes.MapRoute(
    "Default",
    "{controller}/{action}/{id}",
    new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

The code above is way too verbose for my tastes and has the downside that each controller needs to be mentioned at least twice to prevasively apply this url pattern.

Is there some way to generalize this or am I bound to manual labour in this case?

1

There are 1 answers

4
frennky On

You can try something like this:

routes.MapRoute(
                "ProductsList",
                "{pluralizedControllerName}",
                new { controller = "Home", action = "Index" },
                new { pluralizedControllerName = new PluralConstraint() }
                );

            routes.MapRoute(
                "ProductDetails",
                "{controller}/{id}",
                new { controller = "Home", action = "Details" },
                new { id = @"\d+" }
            );

            routes.MapRoute(
                "Default", // Route name
                "{controller}/{action}/{id}", // URL with parameters
                new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
            );

Notice the constraint in second route, it ensures that /Product/Create doesn't get picked by second route so that it gets mapped as third.

For route testing you can use routedebugger, and for writing unit test for routes try MvcContrib-TestHelper. You can get both with NuGet.

EDIT:

You can use this simple pluralizer and then implement something like this:

public class PluralConstraint : IRouteConstraint
    {
        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
        {
            List<string> names = GetControllerNames();//get all controller names from executing assembly
            names.ForEach(n => n.Pluralize(n));
            return names.Contains(values[parameterName]);
        }
    }