ModelState,TempData,ViewModel问题 - 自动覆盖新的viewmodel值

时间:2013-12-18 20:06:00

标签: asp.net-mvc asp.net-mvc-5

最好用代码解释这个问题:

    public async Task<ActionResult> Index()
    {


        if (TempData.ContainsKey("ModelState"))
        {
            ModelState.Merge((ModelStateDictionary)TempData["ModelState"]);


            var viewModelA= new ViewModelA
            {
                 FirstName = "John"
            }
            return View(viewModelA);
        }
     }



    [HttpPost]
    public async Task<ActionResult> IndexPostActionMethod(ViewModelB model)
    {
        if (ModelState.IsValid)
        {

            var result = await DoSomeStuff();
            if (result.Succeeded)
            {
                DoSomeOtherStuff();
            }
            else
            {
                AddErrors(result);
            }
        }





        TempData["ModelState"] = ModelState;
        return RedirectToAction("Index");

    }

这里的问题是,当我发布到IndexPostActionMethod并且DoSomeStuff()由于某种原因返回false时,表单/页面会重定向到重定向到Index并保存在重定向过程中ModelState中的TempData,然后重新显示表单/页面后,ModelState的值(或从哪里获取值?)被设置为a的值@Html.TextBoxFor(m => m.FirstName)而不是我在此处设置的值:var viewModelA = new ViewModelA { FirstName = "John"}。为什么我不能覆盖该值以及从何处获取它?这就像框架使用viewModelA事件中的任何内容自动更新ModelStatDictionary,尽管我创建了一个具有新值的新ViewModelA

1 个答案:

答案 0 :(得分:0)

不要这样做。您应该处理GET-POST-Redirect循环的方式是:

public async Task<ActionResult> Index()
{

    var model = new ViewModel
    {
        FirstName = "John"
    }
    return View(model);
}

[HttpPost]
public async Task<ActionResult> Index(ViewModel model)
{
    if (ModelState.IsValid)
    {

        var result = await DoSomeStuff();
        if (result.Succeeded)
        {
            DoSomeOtherStuff();
        }
        else
        {
            AddErrors(result);
        }
    }

    return View(model);
}

ModelState统治所有。无论您明确传递给视图的是什么,如果ModelState中存在该值,它将优先。使用TempDataModelState传递给另一个视图就是这样的代码味道,“气味”甚至没有覆盖它。

如果您的唯一目标是为GET操作使用一个视图模型,而为POST操作使用另一个不同的视图模型,那么您应该停下来并认真地问自己为什么需要这样做。在我与MVC合作的这些年里,我从来没有这样做,从来没有必要这样做,我无法想象我需要这样做的场景。

<强>更新

所以,根据你在评论中列出的情景,我会这样设计:

public class IndexViewModel
{
    public SomeTabViewModel SomeTab { get; set; }
    public AnotherTabViewModel AnotherTab { get; set; }
    public FooTabViewModle FooTab { get; set; }
}

public class SomeTabViewModel
{
    [Required]
    public string SomeRequiredField { get; set; }
}

public class AnotherTabViewModel
{
    [Required]
    public string AnotherRequiredField { get; set; }
}

public class FooTabViewModel
{
    [Required]
    public string FooRequiredField { get; set; }
}

基本上,您将各个POST部分拆分为视图模型,这些模型完全组成一个大视图模型。然后,模型验证仅遵循容器的实际内部视图模型实例。因此,例如,如果仅回发到FooTab.FooRequiredField,则仅实例化FooTab。另外两个视图模型属性将保持为null并且不会在内部进行验证(即它们具有必需字段并不重要)。