Here's my default route:
routes.MapRouteLowercase(
"Default",
"{country}/{controller}/{action}/{id}",
new {
country = "uk",
controller = "Home",
action = "Index",
id = UrlParameter.Optional
},
new[] { "Presentation.Controllers" }
);
As we know, when someone visits www.domain.com/ MVC's routing will determine the default controller and action to execute based upon the above route, but the URL will remain the same. Is there a built in or elegant way to perform a 301 redirect from www.domain.com/ to www.domain.com/uk/{controller}/{action}/ for every route that uses defaults?
I have created a custom route handler that does the redirect at the route level. Thanks to Phil Haack.
Here is the complete work.
Redirect route handler
public class RedirectRouteHandler : IRouteHandler
{
private string _redirectUrl;
public RedirectRouteHandler(string redirectUrl)
{
_redirectUrl = redirectUrl;
}
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
if (_redirectUrl.StartsWith("~/"))
{
string virtualPath = _redirectUrl.Substring(2);
Route route = new Route(virtualPath, null);
var vpd = route.GetVirtualPath(requestContext,
requestContext.RouteData.Values);
if (vpd != null)
{
_redirectUrl = "~/" + vpd.VirtualPath;
}
}
return new RedirectHandler(_redirectUrl, false);
}
}
Redirect http handler
public class RedirectHandler : IHttpHandler
{
private readonly string _redirectUrl;
public RedirectHandler(string redirectUrl, bool isReusable)
{
_redirectUrl = redirectUrl;
IsReusable = isReusable;
}
public bool IsReusable { get; private set; }
public void ProcessRequest(HttpContext context)
{
context.Response.Status = "301 Moved Permanently";
context.Response.StatusCode = 301;
context.Response.AddHeader("Location", _redirectUrl);
}
}
Route extensions
public static class RouteExtensions
{
public static void Redirect(this RouteCollection routes, string url, string redirectUrl)
{
routes.Add(new Route(url, new RedirectRouteHandler(redirectUrl)));
}
}
Having all these, I can do something like this while mapping routes in Global.asax.cs.
routes.Redirect("", "/uk/Home/Index");
routes.Redirect("uk", "/uk/Home/Index");
routes.Redirect("uk/Home", "/uk/Home/Index");
.. other routes
In my projects, I usually have "IndexRedirect" as default action in my route (whose URL will never be visible) which does nothing but redirecting to the "real" index page (whose URL will always be visible).
You can create this action in a base class of all your controller classes.