3

我有一些代码对于我的一些控制器操作很常见,这些操作被提取到一个私有的“帮助器”方法中,只是为了合并。该方法有望为我“获取”一个对象,尽管它会执行一些健全性/安全性检查,并且可能会将用户重定向到其他操作。

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。

4

5 回答 5

3

您不能在操作中调用 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;
}

更新您可以将此代码放在扩展方法或基本 Controller 类中

public static class ThingyExtensions {

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

}
于 2011-02-18T16:45:15.747 回答
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();
}

当然,你需要确保你没有GetThingy()在 try/catch 中调用,或者如果你这样做了,那么确保你重新抛出异常。

于 2013-09-16T13:16:24.123 回答
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)

于 2011-02-18T16:41:43.163 回答
0

尝试:

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

希望能帮助到你。

于 2011-02-18T16:30:43.380 回答
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;
}

工作得很好,并允许我将代码保留在我想要的地方。挺甜的。

于 2011-02-18T17:03:18.240 回答