.NET MVC: How to redirect response within a helper method

James Maroney picture James Maroney · Feb 18, 2011 · Viewed 7.9k times · Source

I have some code which is common to a number of my controller actions pulled out into a private "helper" method just for consolidation. The method is expected to "get" an object for me, though it performs some sanity/security checks and could potentially redirect the user to other actions.

private Thingy GetThingy(int id)
{
    var thingy = some_call_to_service_layer(id);

    if( null == thingy )
        Response.Redirect( anotherActionUrl );

    // ... many more checks, all more complex than a null check

    return thingy;
}

public ActionResult ActionOne(int id)
{
    var thingy = GetThingy(id);
    // do more stuff
    return View();
}

// ... n more actions

public ActionResult ActionM(int id)
{
    var thingy = GetThingy(id);
    // do more stuff
    return View();
}

This functions properly with the exception that Elmah then notifies me of an exception:

System.Web.HttpException: Cannot redirect after HTTP headers have been sent.

So, my question is: Is there a more correct way to do what I am trying to do? Essentially, all I want is to cause the current action to stop processing and instead return a RedirectToRouteResult.

Answer

David Glenn picture David Glenn · Feb 18, 2011

You cannot call Response.Redirect() in an action without breaking the flow of execution causing an error. Instead you can return an RedirectToRouteResult object or a RedirectResult object. In your action

return Redirect("/path");
//or
return RedirectToAction("actionname");

As in your case however you want to return a Thingy object you will need to seperate out the logic. You could do something like the following (I'm assuming you want to redirect to different actions otherwise Oenning's code will work)

public ActionResult Get(int id) {

  var thingy = GetThingy(id);

  var result = checkThingy(thingy);
  if (result != null) {
    return result;
  }

  //continue...
}

[NonAction]
private ActionResult CheckThingy(Thingy thingy) {

  //run check on thingy
  //return new RedirectResult("path");

  //run another check
  //new RedirectResult("different/path");

  return null;
}

Update You could put this code in an extension method or a base Controller class

public static class ThingyExtensions {

  public static ActionResult Check(this Thingy thingy) {
    //run checks here
  }

}