.NET MVC:如何在辅助方法中重定向响应

时间:2011-02-18 16:28:34

标签: asp.net-mvc redirect controller response.redirect actionmethod

我有一些代码,这些代码对于我的一些控制器操作来说是常见的,这些操作被引入私有“帮助器”方法,仅用于整合。该方法应该为我“获取”一个对象,虽然它执行一些健全/安全检查,并可能将用户重定向到其他操作。

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();
}

除非Elmah通知我异常,否则此功能正常:

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

所以,我的问题是:有没有更正确的方法来做我想做的事情?基本上,我想要的是使当前操作停止处理,而是返回RedirectToRouteResult。

5 个答案:

答案 0 :(得分:2)

您无法在操作中调用Response.Redirect(),而不会中断导致错误的执行流程。相反,您可以返回RedirectToRouteResult对象或RedirectResult对象。在你的行动中

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

在你的情况下,你想要返回一个Thingy对象,你需要分离逻辑。您可以执行以下操作(我假设您要重定向到不同的操作,否则Oenning的代码将起作用

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;
}

更新您可以将此代码放在扩展方法或基本控制器类

public static class ThingyExtensions {

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

}

答案 1 :(得分:2)

执行此操作的一种方法是定义一个异常过滤器来为您处理重定向。

首先,创建一个自定义异常来表示重定向:

public class RedirectException : Exception {

    private readonly string _url;

    public RedirectException(string url) {
        _url = url;
    }

    public string Url { get { return _url; }}

}

然后,定义您的异常过滤器:

public class RedirectExceptionAttribute : FilterAttribute, IExceptionFilter {
    public void OnException(ExceptionContext filterContext) {

        if (filterContext.ExceptionHandled) return;
        if (filterContext.Exception.GetType() != typeof(RedirectException)) return;

        filterContext.Result = new RedirectResult(((RedirectException)filterContext.Exception).Url);
        filterContext.ExceptionHandled = true;
    }
}

全局注册新的异常过滤器,使其适用于所有控制器操作(如果这是您想要的):

// in FilterConfig.cs (MVC 4.0)
public static void RegisterGlobalFilters(GlobalFilterCollection filters) {
    filters.Add(new RedirectExceptionAttribute());
}

现在,无论您想要重定向,只需抛出RedirectException:

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

    if( null == thingy )
        throw new RedirectException( 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();
}

当然,您需要确保不要在try / catch中调用GetThingy(),或者如果确实如此,请确保重新抛出异常。

答案 2 :(得分:0)

尝试:

return RedirectToAction("youraction", "yourcontroller");

希望它有所帮助。

答案 3 :(得分:0)

这是怎么回事。

public ActionResult ActionOne(int id)
{
    var thingy = GetThingy(id);
    if (thingy == null)
        return RedirectToAction("action", "controller");
    // do more stuff
    return View();
}

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

    if( null == thingy )
        return null;

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

    return thingy;
}

顺便说一句,恕我直言,GetThingy(int id)方法应放在其他地方。也许和some_call_to_service_layer(id)在同一个地方。

答案 4 :(得分:0)

好的,我想我已经明白了。显然,你可以随意触发ActionResult的执行。因此辅助方法变为:

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

    if( null == thingy )
        RedirectToAction("myAction").ExecuteResult(ControllerContext);

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

    return thingy;
}

很好地工作,并允许我将代码保存在我想要的位置。很甜蜜。