问题 MVC在视图模型中使用域模型


以下可以做吗?我知道域模型永远不应该在视图中使用,但是在视图模型中使用域模型是否可以?对于一些非常小的模型,为它们创建和管理视图模型似乎不值得。

例如

public class LoginDomainModel
{
    public string Email { get; set; }
    public string Password { get; set; }
    public string DisplayName { get; set; }
    public long UserTypeID { get; set; }      
    public virtual UserType UserType { get; set; } 
}
public class UserTypeDomainModel
{
    public UserType()
    {
        this.Logins = new List<Login>();
    }
    public long UserTypeID { get; set; }
    public string UserType { get; set; }
    public string Description { get; set; }
    public virtual ICollection<Login> Logins { get; set; }
}

public class LoginViewModel
{
    public string Email { get; set; }
    public long UserTypeID {get; set;}

    //Right here
    public List<UserTypeDomainModel> UserTypesSelectList {get; set;}
}

9830
2018-02-23 20:42


起源

所有好的答案,谢谢大家。 - Preston


答案:


我个人在视图中使用域模型 如果它们自然是完全合适的话。这很可能只发生在CRUD本质上的简单项目上(以直接的方式编辑域实体)。为了纯洁,我发现创建域实体的精确副本是浪费时间。

我会 决不 最简单地修改域模型以满足视图的需要。在95%以上的项目中,这就是我自己所处的环境。当你为了视图而污染域名时,就会引入可维护性问题。


9
2018-02-23 20:47



在您的域实体更新并且您的视图尚未更新之前。然后,您会对界面中未显示的新必填字段感到头痛。对于他/她自己,我猜,这只取决于您的域模型的变化可以或确实发生的频率。 - Brad Christie
@BradChristie:在95%的项目中,我将视图模型和域模型与映射层分开(automapper很好)。对于5%的项目(小的,简单的,通常是1人的)来说是过度的。 - Eric J.
可能存在安全隐患。我发现在view / viewmodel中使用域模型实体会大大增加以“叠加”攻击的形式引入安全漏洞的可能性(另请参阅 odetocode.com/blogs/scott/archive/2012/03/11/...)。我还观察到直接在view / viewmodel中使用域实体通常是“贫血域模型”反模式的标志(martinfowler.com/bliki/AnemicDomainModel.html)。我将在view / viewmodel中使用“value objects”,但不使用实体。 - Nathan
如果您使用像Automapper这样的东西,如Scott的博客文章(不包括某些映射)中显示的那样,则会出现安全问题。在一个微不足道的案例中(我认为唯一没有单独的域模型的案例),域模型无论如何都会变得贫血,因为根据定义,主题是微不足道的。只要域名有任何丰富性,我就会因此而拥有单独的域名和视图模型。 - Eric J.


这取决于你所说的“领域模型”。你的意思是EF实体吗?或者你的意思是业务层对象?

将EF实体传递给视图永远不是一个好主意,特别是如果您使用默认模型绑定。如果您不小心,这可能会产生安全问题。虽然如果您对传递给视图的业务对象不小心,可能会出现同样的问题。

视图模型的一个巨大优势是您可以更好地控制数据映射,因此您可以更轻松地验证只发生正确的映射。

这一切都归结为你的应用程序。如果它是一个简单的应用程序,那么进行更复杂的映射可能不值得。如果它是一个复杂的应用程序,它必须存在很长时间,并可能会更新很多..那么你一定要投入精力。


1
2018-02-23 21:03



我指的是EF实体。 - Preston
@Preston - 那是你的数据模型,而不是你的域模型。我的建议仍然适用 - Erik Funkenbusch


由于单独的视图模型和域模型导致的重复感觉,我很长时间都在努力。我断言,因为它们的目的不同,所以不是  重复,但声明这么多相似的属性仍然感觉“错误”。

在非常小的项目中(特别是那些具有高度可信赖的经过身份验证的用户组)我可能只是直接绑定到域模型并完成它。或者,如果视图模型需要不同的结构,我可以混合搭配(如@Eric J.所述)。

然而:ModelBinder将尝试将请求中的值与模型上的属性进行匹配。这意味着您的域模型上的任何属性都可能被(流氓)请求填充。有一些方法可以防止这种情况发生,但对我来说,心灵的安心超过了创建单独视图模型的额外努力。

我没有看到绝对需要为只读,未绑定的值创建单独的视图模型(可能是您的情况下的用户类型列表,尽管 public virtual ICollection<Login> Logins 可以否定这一点)。

或者,您可能希望将域模型投影到面向UI的抽象(例如, IEnumerable<SelectListItem>)。您可以使用 SelectListItems 对于各种输入机制,因此您不会将自己与特定的UI行为联系起来。

即使使用抽象,您仍可能需要验证请求是否包含非法值。例如,也许只有超级管理员可以指定某些 UserTypeDomainModel 标识。无论抽象如何,您仍需要验证这一点。

TLDR: 抽象领域模型尽可能实用,找到适当的抽象(新的视图模型并不总是正确的答案),并且(稍微偏执)关于输入验证。


1
2018-02-23 21:03