user1144
user1144

Reputation:

How do I separate routes that have the same path but do different things?

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?

Upvotes: 2

Views: 323

Answers (2)

George Stocker
George Stocker

Reputation: 57907

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.

Upvotes: 4

Mickel
Mickel

Reputation: 6706

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)

Upvotes: 0

Related Questions