2

假设要求是在 ASP.NET MVC 控制器中成功保存模型后重定向到另一个页面:

[HttpPost]
public ActionResult Index(ViewModel viewModel)
{
   if (ModelState.IsValid)
   {
        // Do save;

        return RedirectToAction("whatever"); // <--- here's the problem 
    }

    // display validation errors and so
    return View(viewModel);
}

除非控制器被呈现为子动作,否则这将正常工作:

@{
    Layout = "my layout";

    Html.RenderAction("something else, a view for example");
    Html.RenderAction("Index action of the above controller"); // <----
}

在这种情况下,RedirectResult 类将检查并查看上下文是否为子操作,并会抛出异常:“不允许子操作执行重定向操作”。

我知道写入响应流已经在进行中,并且无法在此处进行重定向,但是即使该操作是子操作,也必须能够在控制器中的服务器端操作之后重定向到其他页面。我们使用 Layouts 和 RenderActions 来重用页面设计的共享部分。

你将如何在这样的控制器中实现这样的重定向?

编辑:

主要目标是重用执行特定工作的视图/控制器,并将它们拆分为逻辑概念,例如显示一些数据或提供编辑表单。我的方法是使用 RenderAction 将它们的结果呈现到容器中。容器视图(主页的索引操作)充当传统的 asp.net 页面,其布局视图作为母版页,编辑和视图控制器/视图等效于用户控件(模块)。问题是在写入内容后无法重定向响应:

保存问题后 MVC 重定向

4

3 回答 3

1

如果我理解正确,您有一个接受 saveAction 的父控制器,并且在渲染视图时您调用另一个(?) saveAction 作为孩子。
这种流动对我来说感觉不自然。
父操作且只有父操作应处理保存命令。
您可以根据需要渲染任意数量的子操作,只要它们仅用于渲染一些 html(因为这就是视图的作用)。
不要让他们处理重定向或保存,这种工作方式对大学或未来的你来说是透明的。
控制器控制流程,而不是视图。

编辑:
正常设置将有 2 个操作,例如:索引和放置。

public ActionResult Index(){
  //fill model with dropdown data etc
  return View();
} 

public ActionResult Put(viewModel data){
   if (ModelState.IsValid)
   {
        // Do save;
        return RedirectToAction("whatever"); // <--- here's the problem 
    }

    // display validation errors and so
    return View("Index",viewModel);
}

Edit2:如果您返回 View("Index",viewModel) 您将使用其布局生成索引视图,并且验证消息将位于模型状态中。
但是,您的视图应该只有 1 个子操作(如果有多个,则应该有更多,只要它不是保存操作)。您的索引视图可能如下所示:

@{
    Layout = "my layout";
}
Html.RenderAction("something else, a view for example");
@Html.BeginForm("Put","YourController"){
  //all your input controls which will also show the validation errors
}


编辑 3:如果您想重用 html 代码,您应该使用 @Html.Partial 或 Html 辅助扩展方法。请注意,如果您不传递模型,则传递父模型,但您可以传递子模型以匹配部分的类型安全。

它看起来像这样:

@{
    Layout = "my layout";
}
Html.RenderAction("something else, a view for example");
Html.RenderPartial("shared\yourUserControl", Model.PropertyOrSomething);
于 2013-09-25T09:21:20.613 回答
1

我将提交一个新答案,以保持清洁。
正常的 mvc 流程是这样的:
Http 命令到达 1 个控制器,该控制器充当 choirmaster(又名控制器)并调用多个逻辑容器(例如服务/commandHandlers):

public ActionResult Index(){
  var data = _yourService.FetchData();
  return View(data);
}

此控制器呈现 1 个可以有多个部分的视图

@{
    Layout = "my layout";
}
<p>Some html</p>
Html.RenderPartial("A shared partial");
Html.RenderPartial("shared\yourUserControl", Model.PropertyOrSomething);

如果部分包含太多无法生成的逻辑,您可以添加 RenderAction 或创建 htmlHelper 扩展。
但是这些都不应该能够控制您的请求流,在我看来,保存或可以重定向的东西不应该从视图内部调用。
我假设您非常想重用控制器中的代码,因为它变得非常大。
我的建议是通过尽可能多地向上委派逻辑来尝试尽可能多地清除该控制器。
只需查看您的控制器方法 5 秒钟,您就应该了解此操作将做什么,如果不是这样:重构它!:)

于 2013-09-30T09:13:22.053 回答
0

尝试在视图中使用 AJAX 来执行此操作,而不是在控制器中返回 RedirectToAction,而是返回 JSON 对象:

看法:

 $.ajax({
            url: '<%: Html.ResolveUrl("~/ControllerFolder/ControllerName/") %>',
            type: "POST",
            data: data,
            success: function (result) {
                $("#Div").html(result);
                if (result.redirectUrl != null) 
                {
                    window.location = result.redirectUrl;
                }
            }   

        });

控制器:

 [HttpPost]
public ActionResult Index(ViewModel viewModel)
{
   if (ModelState.IsValid)
   {
        // Do save;

        return Json(new { redirectUrl = Url.Action("NewAction", "NewController", RouteValues)}); 
    }

    // display validation errors and so
    return View(viewModel);
}

希望这可以帮助...

于 2013-09-25T08:54:49.393 回答