ASP.NET MVC3和多个HttpPost中的向导

时间:2011-12-18 00:01:58

标签: asp.net-mvc-3 asp.net-mvc-routing

我正在使用http://afana.me/post/create-wizard-in-aspnet-mvc-3.aspx

中描述的向导控件

它工作得很好,但我需要在同一个Controller中有多个HttpPost。在我的场景中,我需要在转移到下一步之前添加到集合中。在该步骤的局部视图中。我有以下设置:

@using (Html.BeginForm("AddJobExperience", "Candidate"))
{
   <input type="submit" value="Add Experience" />
}

当我按下添加体验输入时,它将被路由到

[HttpPost, ActionName("Index")]
public ActionResult Index(CandidateViewModel viewModel)
{
}

而不是

[HttpPost, ActionName("AddJobExperience")]
public ActionResult AddJobExperience(CandidateViewModel col)
{

}

我做错了什么?

3 个答案:

答案 0 :(得分:1)

听起来你仍然有嵌套表格。不要这样做,它是无效的HTML。

这里有2个选项,具体取决于您要实现的目标。如果您想一次一个地发布您的工作经验,然后将它们放在他们自己的@using(Html.BeginForm中,但不要将它们嵌套在外部形式中。当用户单击“添加体验”按钮时,请对该体验进行处理,然后将新视图返回给用户。

如果你想同时发布所有的工作经历,那么将它们全部包装在一个@using(Html.BeginForm中,不要将@using(Html.BeginForm)放在你的部分视图中。参见{{ 3}}。

第二种方法就是你想要实现的目标,为此,你应该使用AJAX为你的收藏添加多个工作经验而不需要完整的回发。然后,您可以执行1次HTTP POST,将集合中的所有作业体验提交给向导控制器。实现这样的功能并不是很困难:

Given I can see the Add Experience button
When I click the Add Experience button
Then I should see a new experience partial view with input fields
And I should enter data in these fields

When I click the Add Experience button a second time
Then I should see another new experience partial view with input fields
And I should enter data in these fields

When I click the Add Experience button a third time
Then I should see a third new experience partial view with input fields
And I should enter data in these fields

When I click the Next button in the wizard
Then my controller will receive data for all 3 experiences I submitted in a single form

答案 1 :(得分:1)

听起来你需要将CandidateViewModel分解为单独的ViewModel,将你的大向导视图分解为单独的视图,这样每个动作的每个步骤都有一个。

第一步,他们添加了工作经验,因此有一个视图,视图模型和一个动作,第二步他们做任何其他事情,你也有一个单独的视图,视图模型和行动。等等

将CandidateViewModel分解为单独的ViewModel意味着您可以只关注该步骤所需的数据,并可以添加验证,然后当他们点击提交时,它会将数据发布到下一步。

然后,当您想要改进UI行为时,添加一些AJAX,并使用类似JQuery UI Tabs的东西,使其更像桌面应用程序中的向导。

答案 2 :(得分:1)

您需要使用 ActionMethodSelectorAttribute ActionNameSelectorAttribute ,它允许在操作上添加新属性,以便在按钮单击时调用不同的操作 在视图中:

@using (Html.BeginForm())
{
   <input type="submit" value="Add Experience" name="AddExperience" />
   <input type="submit" value="Add Experience" name="AddJobExperience" />
}

在应用程序中添加新类FormValueRequiredAttribute,扩展ActionMethodSelectorAttribute类以检查单击了哪个按钮

//controller/FormValueRequiredAttribute.cs

public class FormValueRequiredAttribute :  ActionMethodSelectorAttribute
    {
        public string ButtonName { get; set; }

        public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
        {
            var req = controllerContext.RequestContext.HttpContext.Request;
            return !string.IsNullOrEmpty(req.Form[this.ButtonName]);
        }

    }

然后你应该在动作上添加这个属性来调用相应的动作

在控制器

[HttpPost]
[FormValueRequired(ButtonName = "AddExperience")]
public ActionResult Index(CandidateViewModel viewModel)
{
  return View();
}

[HttpPost]
[ActionName("Index")]
[FormValueRequired(ButtonName = "AddJobExperience")]
public ActionResult AddJobExperience_Index(CandidateViewModel viewModel)
{
  return View();
}

请注意,如果您在Index.cshtml中使用Html.BeginForm方法,则不需要在Index Action上指定ActionName属性,现在 AddJobExperience_Index 与Index Action相同。