2

The following route Page/View/Id would go to the View Method in the Page Controller. I'd also like the following route:

/{page-title}

to go to the same method. That's so I could have URLs like the following:

http://www.mysite.com/This-Is-a-Page

How do I configure this, considering This-Is-a-Page might be a controller also?

George Stocker
  • 57,289
  • 29
  • 176
  • 237
  • This has been posted twice and is the same as: http://stackoverflow.com/questions/2591524/asp-net-mvc-routes – Leom Burke Apr 07 '10 at 10:16

2 Answers2

4

If both your "controller" routes and "page" routes (see below) use the same /something, then you're going to have to implement the following rules:

At the top of your routes:

route. MapRoute(
    "ControllerRoute"
    "{controller}",
    new { controller = "Home", action = "Index" }
    new { controller = GetControllerNameRegex() }
);

route.MapRoute(
    "PageRoute",
    "{pageSlug}"
    new { controller = "Page", action = "ShowPage" }
);
  • No page can have a name that matches any controller in use.
  • Or no controller can have the name that matches any page in use.

Since you can't really do the latter programmatically, but you can do the former programmatically, you can add a custom constraint to your controller routes, so that it will only hit if you happen to type the name of a controller:

private static string GetControllerNameRegex()
{
    var controllerNamesRegex = new StringBuilder();
    List<string> controllers = GetControllerNames();
    controllers.ForEach(s =>
            controllerNamesRegex.AppendFormat("{0}|", s));
    return controllerNamesRegex.ToString().TrimEnd('|');
}

private static List<Type> GetSubClasses<T>()
{
    return Assembly.GetCallingAssembly().GetTypes().Where(type => 
           type.IsSubclassOf(typeof(T))).ToList();
}

public List<string> GetControllerNames()
{
    List<string> controllerNames = new List<string>();
    GetSubClasses<Controller>().ForEach(type => controllerNames.Add(type.Name));
    return controllerNames;
}

NB: Best course would be to make sure not to have any pages named after your controller, and you could use the above code to enforce that at runtime.

Community
  • 1
  • 1
George Stocker
  • 57,289
  • 29
  • 176
  • 237
0

You might be able to add a catch all, like so (place this after the default routes):

routes.MapRoute(
    null,
    "{*query}",
    new { controller = "SomeController", action = "SomeAction" }
);

And the action signature would look like this:

public ActionResult(string query)
Mickel
  • 6,658
  • 5
  • 42
  • 59
  • This only works if you define it before the default, if defined after default, it will assume title is a controller –  Apr 07 '10 at 14:47
  • 1
    Not if there is no controller for that title. This route catches all that does not match any of the above. – Mickel Apr 07 '10 at 15:37