In this recipe, we will take a look at a great use of the wildcard route. We will show how to make a single route that handles multiple URLs from /Sports/Football/Padding/Rawlings/ShoulderPads to /Aquariums/100-Gallon/Stands/Marineland/Monterey-Stand
. We will also take this concept one step further by supporting additional commands other than just a Get content
type scenario. We will also add support Delete, Post
, and Edit
, so that our single route can support an inline style content management solution.
Global.asax
file. In the routing section, add a new route definition to the bottom of the list. This route will not specify a controller, an action, or any other parameters. Instead it will have only a wildcard option to catch all requests that make it to the bottom of our route dictionary. This route will use the Home Controller and a Catalog
action that we will create shortly. Also, this route will use a custom RouteHandler
called CatalogRouteHandler
.Global.asax:
routes.MapRoute("DbContent", "{*path}", new {controller = "Home", action = "Catalog"}) .RouteHandler = new CatalogRouteHandler();
Catalog
action. This action should technically not be reached by this style of request, but it can be used as an entry page to your catalog.Controllers/HomeController.cs:
public ActionResult Catalog() { return View(); }
CatalogRouteHandler
. This class will implement the IRouteHandler
, which requires that a GetHttpHandler
method be specified.Models/CatalogRouteHandler.cs:
public class CatalogRouteHandler : IRouteHandler { public IHttpHandler GetHttpHandler(RequestContext requestContext) { ... } }
Models/CatalogRouteHandler.cs:
string path = requestContext.RouteData.Values["path"] as string; //remove trailing slash if there is one if (path.EndsWith("/")) path = path.Substring(0, path.Length - 1); if(path != null && path.Contains("/")) //valid path parameter { int lastIndex = path.LastIndexOf('/'), if(lastIndex >= 0) { string commandName = path.Substring(lastIndex + 1); ... } }
switch
statement to achieve this. Once we locate the type of command we are going to use, we will then modify our current route definition to have the appropriate action as well as the cleaned and adjusted path.Models/CatalogRouteHandler.cs:
switch(commandName.ToUpper()) { case "GET": //get the catalog item requestContext.RouteData.Values["action"] = "Get"; //add the path minus the command back in requestContext.RouteData.Values["path"] = path.Substring(0, lastIndex); break; case "DELETE": //delete catalog item requestContext.RouteData.Values["action"] = "Delete"; //add the path minus the command back in requestContext.RouteData.Values["path"] = path.Substring(0, lastIndex); break; case "EDIT": //edit catalog item requestContext.RouteData.Values["action"] = "Edit"; //add the path minus the command back in requestContext.RouteData.Values["path"] = path.Substring(0, lastIndex); break; case "POST": //save catalog item (insert/update) requestContext.RouteData.Values["action"] = "Post"; //add the path minus the command back in requestContext.RouteData.Values["path"] = path.Substring(0, lastIndex); break; default: //we will allow nothing to act as a GET requestContext.RouteData.Values["action"] = "Get"; //add the path minus the command back in requestContext.RouteData.Values["path"] = path; break; }
Models/CatalogRouteHandler.cs:
... } return new MvcHandler(requestContext); }
Controllers/HomeController.cs:
[HandleError] public class HomeController : Controller { ... public ActionResult Get(string path) { return View(); } public ActionResult Delete(string path) { return View(); } public ActionResult Post(string path) { return View(); } public ActionResult Edit(string path) { return View(); } }
/Home/About
or /Home/Index
or /Account/LogOn
, and so on!As with most other recipes of this type, we have hooked into yet another extension point of the MVC framework. We have defined a catch all route at the bottom of our route dictionary. When this route is picked for a request, we shell out to a custom route handler, which doctors the route to suit its needs and returns the appropriate route definition.
When researching a CMS system that I was building, I needed a recipe of this nature. While this post doesn't quite do all that I would have liked, it got me pretty close to what I was trying to achieve. Credit where credit is due! Thanks chris166. http://stackoverflow.com/questions/1023252/asp-net-mvc-complex-routing-for-tree-path.