If you want to change controllers dynamically, the place to do it is in a custom RouteBase
subclass. Redirection is a bad idea because your server will issue a 301 or 302 to the client's browser telling it to lookup a new location on the server. That round-trip is wasteful and unnecessary.
public class SwitcherRoute : RouteBase
{
public override RouteData GetRouteData(HttpContextBase httpContext)
{
RouteData result = null;
// Trim the leading slash
var path = httpContext.Request.Path.Substring(1);
// Check that the request is what you are interested in
if (path.Equals("home/about", StringComparison.OrdinalIgnoreCase))
{
result = new RouteData(this, new MvcRouteHandler());
if (/* some (preferably cached) condition */)
{
result.Values["controller"] = "Home";
result.Values["action"] = "About";
}
else
{
result.Values["controller"] = "Alternate";
result.Values["action"] = "About";
}
}
// IMPORTANT: Always return null if there is no match.
// This tells .NET routing to check the next route that is registered.
return result;
}
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
VirtualPathData result = null;
var controller = Convert.ToString(values["controller"]);
var action = Convert.ToString(values["action"]);
if (action.Equals("About", StringComparison.OrdinalIgnoreCase))
{
if (controller.Equals("Home", StringComparison.OrdinalIgnoreCase) ||
controller.Equals("Alternate", StringComparison.OrdinalIgnoreCase))
{
return new VirtualPathData(this, "home/about");
}
}
// IMPORTANT: Always return null if there is no match.
// This tells .NET routing to check the next route that is registered.
return result;
}
}
Usage
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.Add(
name: "AboutPage",
item: new SwitcherRoute());
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Note that you can make your custom route more flexible by accepting constructor parameters or even inheriting from the built-in Route
class.
Also note that routes run on every request, so you should cache any expensive lookup operations as in this example.