【问题标题】:Asp.NET MVC - DataAnnotations and ModelState.IsValid too invasive into the domain model?Asp.NET MVC - DataAnnotations 和 ModelState.IsValid 太侵入域模型?
【发布时间】:2013-12-28 08:16:08
【问题描述】:

我正在从书 Pro ASP.NET MVC 4 中学习 ASP.NET MVC(顺便说一句,到目前为止我很喜欢)。

我还在开始的章节中,它向我展示了System.ComponentModel.DataAnnotations 命名空间属性,如何在我的模型类中添加这些注释,然后如何使用它们来检查模型是否有效(ModelState.IsValid in Controller)。

例如:

public class GuestResponse
{
    [Required(ErrorMessage = "Please enter your name"]
    public string Name { get; set; }
}

...

public ViewResult RsvpForm(GuestResponse guestResponse)
{
    if(ModelState.IsValid)
    {
        return View("Thanks", guestResponse);

    }

}

有几件事让我感到不安。

  1. 为什么我希望在我的域模型中散布一堆属性?我喜欢我的领域模型纯粹并且没有任何特定于实现的东西,任何现实世界的模型都太复杂而不能像这样使用声明式验证。
  2. 验证属性的ErrorMessage 参数是否与View 有点相关?类似的东西不属于UI 层吗?例如...如果由于空间限制我想要移动版本而不是说“请输入您的姓名”而是说“需要姓名”怎么办?但它在我的模型中!
  3. 为什么要使用ModelState.IsValid来判断模型的状态?模型不应该告诉我吗?我知道ModelState 正在使用我的模型中DataAnnotations 属性,但这似乎只适用于非常简单的模型。更复杂的模型甚至可能没有有效/无效状态,它可能只有不同的阶段和状态。我在这里有点漫无边际,但我不喜欢声明性地说明是什么使我的模型有效或无效的想法。

对这些想法的任何建议、保证或验证将不胜感激。

【问题讨论】:

    标签: asp.net-mvc-4 entity-framework-5 data-annotations separation-of-concerns


    【解决方案1】:

    以下是我对您问题的回答:

    1) 为什么我希望在我的域模型中散布一堆属性?我喜欢我的领域模型纯粹并且没有任何东西 具体实现,任何现实世界的模型都太复杂了 像这样使用声明式验证。

    你绝对不想要这个。您想要的是拥有一个专为您的视图目的而设计的视图模型。包含数据注释的是这个视图模型,而不是您的域模型。然后控制器将在域模型和视图模型之间进行映射,并将视图模型传递给视图。将视图模型视为一个或多个域模型的投影。为了简化您的域和视图模型之间的映射,您可以签出AutoMapper。基本的经验法则是视图不应该知道你的领域模型。

    2) 验证属性的 ErrorMessage 参数是不是有点与 View 相关?类似的东西不属于 UI 层?例如......如果由于空间限制我想要 移动版不要说“请输入您的姓名”,而是说“姓名 必需”?但它在我的模型中!

    完全同意你的看法。这就是为什么你应该有一个专门为视图目的设计的视图模型类的原因。

    3) 为什么要使用ModelState.IsValid来判断状态 模型?模型不应该告诉我吗?我知道 ModelState 是 利用我模型中的 DataAnnotations 属性,但是 这似乎只适用于非常简单的模型。一个更 复杂模型甚至可能没有有效/无效状态,它可能只是 有不同的阶段和状态。我在这里有点漫不经心,但我不 就像声明性地说明是什么让我的模型有效的想法或 无效。

    我再次同意你的看法。声明式验证(例如您使用 Data Annotations 开箱即用的内容)非常适合 Hello World 类型的应用程序,但是一旦您开始使用复杂的验证规则编写真实世界的应用程序,您很快就会意识到声明式方法根本不切芥末。正是出于这个原因,我使用FluentValidation.NET。它为您提供了一种非常优美流畅的语法来表达任意复杂的验证规则,它integrates easily with ASP.NET MVC 并允许unit test your validation rules 完全隔离。

    【讨论】:

    • 个人不会说绝对,需要更复杂的解决方案的时候需要能够挑挑拣拣。同样,虽然 FluentValidation.NET 非常好,但它也可以验证 ViewModel 或简单的域模型。复杂领域模型的验证是领域本身的责任。
    • 我同意使用视图模型会增加另一层复杂性,但这绝对是正确的方法。我见过很多人开始项目时告诉他们这将是一个小型应用程序,他们不想使用视图模型等......然后逐渐增加复杂性并最终陷入他们必须完全废弃所有东西的情况白手起家。恕我直言,直接在视图中使用域模型非常适合做一些演示,这是一种 hello world 类型的应用程序,但是一旦您开始从事业务,视图模型是唯一的方法。
    • 就验证而言,我们来看下面的例子:如何使用数据注释对依赖属性进行条件验证?例如,您的模型上有 2 个属性:City 和 Zip。仅当 City 具有值时才需要 Zip。这似乎是一个非常普遍的要求。您更喜欢这里的哪一个:stackoverflow.com/a/9277886/29407 可能性 2 或 3?
    • @Alistair FluentValidation(或任何其他验证框架)应仅验证用户输入(视图模型)。领域,贫血与否都应该关心自己。我个人在 fluent 验证器中使用域值对象来确保用户输入有效。所以在某种程度上,域仍然只在不同的层进行一些验证
    • 除了 MikeSW 所说的,您的视图模型与域模型的验证规则通常不同。例如,您的 CreateUserViewModel 将没有 Id 属性,而您的 UpdateUserViewModel 将具有 Id 属性,并且此属性是必需的。另一方面,您的 User 域模型将具有一些 Id 属性,该属性表示主键或数据存储中与视图模型验证无关的任何内容。
    【解决方案2】:

    数据注释只是其中一种方式。您还可以使用 Fluent API 来定义数据库架构和映射 ER。注释与前端 jQuery 验证代码紧密结合,因此派上用场也更容易。 是的,如果您不想在业务逻辑中添加注释,您可以在 UI 层中使用视图模型。这完全取决于应用程序的范围和大小,以及您最终将使用的视图模型的范围。

    这里有一些博客你可以参考一下,以消除你对 EF 的疑虑

    http://msdn.microsoft.com/en-us/data/jj591620.aspx

    希望这能让你继续前进。

    【讨论】:

      【解决方案3】:

      这个问题的答案很大程度上取决于您试图解决的问题。例如,您的域是否包含复杂的业务逻辑或者是基于 CRUD 的应用程序。您应该尝试选择最适合您要解决的问题。

      1. 我想在考虑这些“领域模型”时有两个极端,它们可以只是数据库和 UI 之间的数据传输对象,或者,它们可以是对业务问题建模的复杂 DDD 类型对象。如果它们是前者,那么为什么不让它们尽可能简单。另一方面,使用视图和数据库之间共享的“单一”模型很难很好地实现复杂的业务领域。实际上,您可能处于中间位置。

      2 和 3。是的,但这对您的“备注”应用程序有影响吗,对于您的运输应用程序呢?

      【讨论】:

      • 谢谢。通常我使用的领域模型非常复杂,并且包含很多业务逻辑。
      猜你喜欢
      • 2012-06-09
      • 1970-01-01
      • 1970-01-01
      • 2011-02-22
      • 1970-01-01
      • 1970-01-01
      • 2011-06-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多