MVC redirect to default route

2019-02-07 07:16发布

问题:

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?

回答1:

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


回答2:

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.