如果“ViewModel”指的是用于 MVC 视图的 DTO(相对于 MVVM 框架中的 ViewModel),那么不,这不是一个好的设计。
首先,从安全角度来看,这是一个糟糕的设计,因为:
您依赖您的视图来实际执行安全规则(例如,通过检查AdminRole 有条件地呈现内容)。这很难有效地测试或审查。
由于错误或编码草率,您可能会无意中将私人安全信息泄露给客户端。
如果没有适当的清理,您可能会在POST、PUT 或其他“写入”操作中意外使用此属性。
但更重要的是,从 MVC 的角度来看,这简直就是糟糕的设计,因为它错过了 View Model 应有的意义。
视图模型旨在包含有关如何显示视图的信息。他们应该抽象原本会进入视图的业务逻辑,而不仅仅是传递。
这个场景的更好的设计是这样的:
视图模型
public class IndexViewModel
{
public bool CanDeleteItems { get; set; }
public bool IsAdminMenuVisible { get; set; }
// Other properties...
}
控制器
public ActionResult Index()
{
return View(new IndexViewModel
{
CanDeleteItems = User.IsInRole("ContentManager"),
IsAdminMenuVisible = User.IsInRole("Administrator"),
// Other properties...
});
}
查看
@if (Model.IsAdminMenuVisible)
{
<!-- Markup for admin menu -->
}
@foreach (var item in Model.Items)
{
<!-- Markup for item -->
<button type="submit" @((Model.CanDeleteItems) ? "disabled" : "")>Delete</button>
}
这里的想法是 ViewModel 只包含特定于视图本身的属性。视图无法决定在什么业务条件下某个元素可见、禁用等。视图模型将告诉它确切显示什么以及何时显示,使用以它们绑定到的特定视图元素命名的属性。
这对可维护性也更好。如果您决定如果用户拥有“ContentManager”或“Administrator”角色,他们应该能够删除项目,会发生什么?在您的版本中,您最终会修改视图;在上述版本中,您只需要修改控制器。如果您发现自己不得不修改视图而不是更改外观和感觉,这意味着您在架构中犯了一个错误。安全检查应该发生在控制器中。
注意,根据您的架构风格,您也可以在 ViewModel 中将这些作为派生属性实现,例如:
public class IndexViewModel
{
private readonly IPrincipal user;
public IndexViewModel(IPrincipal user)
{
this.user = user;
}
public bool CanDeleteItems
{
get { return user.IsInRole("ContentManager"); }
}
public bool IsAdminMenuVisible
{
get { return user.IsInRole("Administrator"); }
}
}
这是一种更面向对象的设计,并且同样可以接受,因为视图模型实际上并不向视图公开底层规则,并且与控制器一样可测试。就像我上面所说的,这更多的是个人喜好问题,以及您是希望 ViewModel 是智能的(如在 MVVM 中)还是只是愚蠢的 DTO(更多的 MVC 风格)。