title: Mvc Custom Route and Breadcrumb Strategies?
body: <p>I'm creating an ASP.net MVC / Entity Framework shopping cart to get more familiar with the technology. One of the features I wanted to have was URLs based of off unique slugs instead of embedding the entity ids into the URL. Some examples:</p>
  
  <ul>
  <li>/</li>
  <li>/information</li>
  <li>/information/about-us</li>
  <li>/information/contact-us</li>
  <li>/mens-clothing</li>
  <li>/mens-clothing/mens-shirts</li>
  <li>/mens-clothing/mens-shirts/test-tshirt</li>
  </ul>
  
  <p>The slugs are unique across all content types, but for example, test-tshirt could appear in multiple categories:</p>
  
  <ul>
  <li>/mens-clothing/mens-shirts/test-tshirt</li>
  <li>/mens-clothing/clearance/test-tshirt</li>
  </ul>
  
  <p>I created a custom route that takes the last slug in the path and uses it to look up the current page.</p>
  
  <pre><code>public class SlugRoute : RouteBase
  {
      public override RouteData GetRouteData(HttpContextBase httpContext)
      {
          string path = HttpContext.Current.Request.Path.TrimStart('/').TrimEnd('/');
  
          if (string.IsNullOrEmpty(path))
              path = "home";
  
          string[] slugs = path.Split('/');
  
          string slug = slugs[slugs.Length - 1];
  
          CatalogPage page = Token.Instance.DB.Pages.SingleOrDefault(p =&gt; p.UrlSlug == slug);
          if (page != null)
          {
              // Cache current page in context
              HttpContext.Current.Items["CurrentPage"] = page;
  
              // Set up route data
              RouteData data = new RouteData(this, new MvcRouteHandler());
              data.Values["action"] = "Index";
              data.Values["id"] = page.Id;
              data.DataTokens.Add("namespaces", new string[] { "MyProject.Presentation.Controllers" });
  
              // Set controller value if specified in db, or set based on entity type
              if (!string.IsNullOrEmpty(page.Controller))
                  data.Values["controller"] = page.Controller;
              else if (page.GetUnproxiedType() == typeof(CategoryPage))
                  data.Values["controller"] = "Category";
              else if (page.GetUnproxiedType() == typeof(ProductPage))
                  data.Values["controller"] = "Product";
              else
                  data.Values["controller"] = "Content";
              return data;
          }       
          return null;
      }
  
      public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
      {
          return null;
      }
  }
  </code></pre>
  
  <p>This works well and I have good flexibility in implementing custom logic and display templates (the content types have a "View" property as well so I can dynamically set the view in the controller).</p>
  
  <p>However, I stumble a little bit when it comes to implementing breadcrumbs. The quick and dirty way would be to use the path from the URL, do a query for each slug in the path, and ignore whether or not the page is actually a child of the category. Another solution would be to use something like <a href="https://github.com/maartenba/MvcSiteMapProvider" rel="nofollow">MvcSiteMapProvider</a> and build up an XML tree as content is added on the backend... I'm unsure how well this specific implementation will work because it seems to be pretty focused on the standard {controller}/{action}/{id} route pattern.</p>
  
  <p>What other types of implementations have you used or seen?</p>