在部分视图中保存后重定向

时间:2013-09-25 08:36:38

标签: asp.net-mvc

假设要求是在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);
}

除非控制器呈现为Child Action:

,否则这样可以正常工作
@{
    Layout = "my layout";

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

在这种情况下,RedirectResult类将检查并查看上下文是子操作并抛出异常:&#34;不允许子操作执行重定向操作&#34;。

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

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

编辑:

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

MVC Redirect after save problem

3 个答案:

答案 0 :(得分:1)

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

编辑:
正常设置将有2个动作,例如:Index和Put。

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

答案 1 :(得分:1)

我会提交一个新答案,以保持清洁 正常的mvc流程如下:
Http命令到达1个控制器,它充当choirmaster(aka控制器)并调用几个逻辑容器(例如services / 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秒钟,你应该知道这个动作会做什么,如果不是这样的话:重构它! :)

答案 2 :(得分: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);
}

希望这会有所帮助......