我对使用ViewModel相当新,我想知道,ViewModel是否可以将域模型的实例包含为属性,或者这些域模型的属性是否应该是ViewModel本身的属性?例如,如果我有一个班级Album.cs
public class Album
{
public int AlbumId { get; set; }
public string Title { get; set; }
public string Price { get; set; }
public virtual Genre Genre { get; set; }
public virtual Artist Artist { get; set; }
}
您是否通常让ViewModel保留Album.cs
类的实例,或者您是否让ViewModel具有每个Album.cs
类'的属性?属性。
public class AlbumViewModel
{
public Album Album { get; set; }
public IEnumerable<SelectListItem> Genres { get; set; }
public IEnumerable<SelectListItem> Artists { get; set; }
public int Rating { get; set; }
// other properties specific to the View
}
public class AlbumViewModel
{
public int AlbumId { get; set; }
public string Title { get; set; }
public string Price { get; set; }
public IEnumerable<SelectListItem> Genres { get; set; }
public IEnumerable<SelectListItem> Artists { get; set; }
public int Rating { get; set; }
// other properties specific to the View
}
答案 0 :(得分:16)
意见因技术最佳实践和个人偏好而异。
在视图模型中使用域对象,甚至使用域对象作为模型,并没有什么错误,很多人都这样做。有些人强烈建议为每个视图创建视图模型,但就个人而言,我觉得许多应用程序都是由开发人员过度设计的,他们学习并重复他们习以为常的方法。事实上,有几种方法可以使用较新版本的ASP.NET MVC来实现目标。
当您为视图模型以及业务和持久层使用通用域类时,最大的风险是模型注入。向模型类添加新属性可以在服务器边界之外公开这些属性。攻击者可能会看到他不应该看到的属性(序列化)并更改他不应该改变的值(模型绑定器)。
为防止注射,请使用与您的整体方法相关的安全实践。如果您计划使用域对象,请确保在控制器中使用白名单或黑名单(包含/排除)或通过模型绑定器注释。黑名单更方便,但是编写未来修订版的懒惰开发人员可能会忘记它们或者不了解它们。白名单([Bind(Include = ...)]是强制性的,在添加新字段时需要注意,因此它们充当内联视图模型。
示例:
[Bind(Exclude="CompanyId,TenantId")]
public class CustomerModel
{
public int Id { get; set; }
public int CompanyId { get; set; } // user cannot inject
public int TenantId { get; set; } // ..
public string Name { get; set; }
public string Phone { get; set; }
// ...
}
或
public ActionResult Edit([Bind(Include = "Id,Name,Phone")] CustomerModel customer)
{
// ...
}
第一个示例是在整个应用程序中强制执行多租户安全的好方法。第二个示例允许自定义每个操作。
在您的方法中保持一致,并清楚地记录项目中用于其他开发人员的方法。
我建议您始终使用视图模型进行登录/配置文件相关功能,以强制自己“编组”Web控制器和数据访问层之间的字段作为安全练习。