Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct Controller code for a 301 Redirect

I am designing a new dynamic site from a static site. I have the route all sorted but I have a question on my Action method.

Below is the code but when testing and looking at the headers that Firebug reports, if I take out the Response.End it is a 302 redirect I assume because I set the 301 but then call another action which makes it a 302, but if I put in the Response.End I get a 301.

I am guessing that adding the Response.RedirectLocation is actually doing the 301 redirect so do I therefore change my return value to EmptyResult or null even though that line of code will never get executed just so the app compiles?

public ActionResult MoveOld(string id)
{
    string pagename = String.Empty;

    if(id == "2")
    {
      pagename = WebPage.SingleOrDefault(x => x.ID == 5).URL;
    }

    Response.StatusCode = 301;
    Response.StatusDescription = "301 Moved Permanently";
    Response.RedirectLocation = pagename;
    Response.End();

    return RedirectToAction("Details", new { pageName = pagename });
}
like image 501
Jon Avatar asked Nov 07 '09 16:11

Jon


People also ask

What is a 301 response code?

The HyperText Transfer Protocol (HTTP) 301 Moved Permanently redirect status response code indicates that the requested resource has been definitively moved to the URL given by the Location headers. A browser redirects to the new URL and search engines update their links to the resource.

What is the code for redirect?

What is a redirect? A redirect is a way to send both users and search engines to a different URL from the one they originally requested. The three most commonly used redirects are 301, 302, and Meta Refresh.


2 Answers

I echo Levi's comments. This is not the job of the controller. I have tended to use this custom ActionResult for 301's. Below is a modified version with more options.

For ASP.NET MVC v2+, use RedirectResult.

public class PermanentRedirectResult : ActionResult
{
  public string Url { get; set; }

  public PermanentRedirectResult(string url)
  {
    Url = url;
  }

  public PermanentRedirectResult(RequestContext context, string actionName, string controllerName)
  {
    UrlHelper urlHelper = new UrlHelper(context);
    string url = urlHelper.Action(actionName, controllerName);

    Url = url;
  }

  public PermanentRedirectResult(RequestContext context, string actionName, string controllerName, object values)
  {
    UrlHelper urlHelper = new UrlHelper(context);
    string url = urlHelper.Action(actionName, controllerName, values);

    Url = url;
  }

  public PermanentRedirectResult(RequestContext context, string actionName, string controllerName, RouteValueDictionary values)
  {
    UrlHelper urlHelper = new UrlHelper(context);
    string url = urlHelper.Action(actionName, controllerName, values);

    Url = url;
  }

  public override void ExecuteResult(ControllerContext context)
  {
    if (context == null)
    {
      throw new ArgumentNullException("context");
    }
    context.HttpContext.Response.StatusCode = 301;
    context.HttpContext.Response.RedirectLocation = Url;
    context.HttpContext.Response.End();
  }
}

Usage in the action

//Just passing a url that is already known
return new PermanentRedirectResult(url);

//*or*

//Redirect to a different controller/action
return new PermanentRedirectResult(ControllerContext.RequestContext, "ActionName", "ControllerName");
like image 98
Dan Atkinson Avatar answered Oct 17 '22 22:10

Dan Atkinson


The controller should not be responsible for setting the 301 and redirect location. This logic should be encapsulated within an ActionResult, and the controller should return an instance of that ActionResult. Keep in mind that the method Response.End() does not return (it throws an exception); lines that follow it will not execute.

like image 21
Levi Avatar answered Oct 18 '22 00:10

Levi