title: ASP.NET MVC: Routing custom slugs without affecting performance
body: <p>I would like to create custom slugs for pages in my CMS, so users can create their own SEO-urls (like Wordpress).</p>
  
  <p>I used to do this in Ruby on Rails and PHP frameworks by "abusing" the 404 route. This route was called when the requested controller could not be found, enabling me te route the user to my <strong>dynamic pages controller</strong> to parse the slug (From where I redirected them to the real 404 if no page was found). This way the database was only queried to check the requested slug.</p>
  
  <p>However, in MVC the catch-all route is only called when the route does not fit the default route of <code>/{controller}/{action}/{id}</code>.</p>
  
  <p>To still be able to parse custom slugs I modified the <code>RouteConfig.cs</code> file:</p>
  
  <pre><code>public class RouteConfig
  {
      public static void RegisterRoutes(RouteCollection routes)
      {
          routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
  
          routes.MapHttpRoute(
              name: "DefaultApi",
              routeTemplate: "api/{controller}/{id}",
              defaults: new { id = RouteParameter.Optional }
          );
  
          RegisterCustomRoutes(routes);
  
          routes.MapRoute(
              name: "Default",
              url: "{controller}/{action}/{id}",
              defaults: new { Controller = "Pages", Action = "Index", id = UrlParameter.Optional }
          );
      }
  
      public static void RegisterCustomRoutes(RouteCollection routes)
      {
          CMSContext db = new CMSContext();
          List&lt;Page&gt; pages = db.Pages.ToList();
          foreach (Page p in pages)
          {
              routes.MapRoute(
                  name: p.Title,
                  url: p.Slug,
                  defaults: new { Controller = "Pages", Action = "Show", id = p.ID }
              );
          }
          db.Dispose();
      }
  }
  </code></pre>
  
  <p>This solves my problem, but requires the <code>Pages</code> table to be fully queried for every request. Because a overloaded show method (<code>public ViewResult Show(Page p)</code>) did not work I also have to retrieve the page a second time because I can only pass the page ID.</p>
  
  <ol>
  <li>Is there a better way to solve my problem?</li>
  <li>Is it possible to pass the Page object to my Show method instead of the page ID?</li>
  </ol>