验证失败后重新填充嵌套的ViewModels

时间:2012-01-10 19:37:17

标签: asp.net-mvc validation viewmodel

我们有视图模型,其中包含其他视图模型。例如,我在几乎所有其他视图模型下都有一个导航视图模型,因为每个屏幕都有导航。构建导航视图模型的逻辑在一个地方。

问题是在POST期间,引用类型(如视图模型)将被清空。这是有道理的,但这意味着如果我们需要再次返回视图,我们必须部分重建视图模型,例如验证失败时。我们不能只从头开始重建视图模型,因为它们保存了部分输入的数据。

现在,我们手动检查ModelState.IsValid并手动重建每个子视图模型。我们通过创建构建我们的视图模型的名为Builders的类型来消除重复逻辑。这些构建器目前有三种构建方法:一种用于构建空白视图模型,一种用于处理验证问题,另一种用于处理编辑。

ViewModel Build(<params>) // create
void Build(ViewModel, <params>) // validation error
ViewModel Build(DBObject, <params>) // edit

这似乎是一种重大的矫枉过正。 90%的情况下,如果属性是另一个视图模型,则应该重建它。如果有第三方库将视图模型映射到构建器类,只根据需要构建它们,那就太好了。当然,这将是递归的,并且也构建子视图模型。而不是:

return View(viewModel) 

return RedirectToAction("index", "home", viewModel) 

只会有帮助者:

return View<ViewModel>()

return RedirectToAction<ViewModel>("index", "home")

1 个答案:

答案 0 :(得分:3)

  

例如,我在几乎每一个都有一个导航视图模型   其他视图模型,因为每个屏幕都有导航。的逻辑   构建导航视图模型在一个地方。

这似乎是分割视图模型并使用Html.Action helper从单独的子操作渲染导航菜单的绝佳选择。

这样您就不必再担心主要操作和视图模型了。

所以我的想法是你可以让菜单控制器负责生成菜单:

public class MenuController: Controller
{
    private readonly IMenuRepository _repository;
    public MenuController(IMenuRepository repository)
    {
        _repository = repository;
    }

    [ChildActionOnly]
    public ActionResult Index()
    {
        var menu = _repository.GetMenu();
        var menuViewModel = Mapper.Map<Menu, MenuViewModel>(menu); // AutoMapper example
        return View(menuViewModel);
    }
}

然后是相应的Index视图,它将是仅包含菜单标记的部分:

@model MenuViewModel
@{
    Layout = null;
}
<ul>
   <li>....
   <li>....
</ul>

然后你可以在你定义的位置渲染_Layout中的菜单:

@Html.Action("index", "menu")

然后你可以拥有与这个菜单渲染完全分离的控制器和视图模型。