我有一些代码,这些代码对于我的一些控制器操作来说是常见的,这些操作被引入私有“帮助器”方法,仅用于整合。该方法应该为我“获取”一个对象,虽然它执行一些健全/安全检查,并可能将用户重定向到其他操作。
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。
答案 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;
}
很好地工作,并允许我将代码保存在我想要的位置。很甜蜜。