最好用代码解释这个问题:
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
。
答案 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
中存在该值,它将优先。使用TempData
将ModelState
传递给另一个视图就是这样的代码味道,“气味”甚至没有覆盖它。
如果您的唯一目标是为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并且不会在内部进行验证(即它们具有必需字段并不重要)。