我们有视图模型,其中包含其他视图模型。例如,我在几乎所有其他视图模型下都有一个导航视图模型,因为每个屏幕都有导航。构建导航视图模型的逻辑在一个地方。
问题是在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")
答案 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")
然后你可以拥有与这个菜单渲染完全分离的控制器和视图模型。