【问题标题】:Does ASP.Net MVC 2 validation need some more thought in terms of patterns and use?ASP.Net MVC 2 验证是否需要在模式和使用方面进行更多思考?
【发布时间】:2011-01-12 00:31:42
【问题描述】:

这里是大地。像大多数人一样,我有我的领域对象和我的视图模型。我喜欢使用视图模型的想法,因为它允许专门为给定的视图上下文创建模型,而无需更改我的业务对象。

我遇到的问题是在我的域对象上定义类型级别验证并将这些规则发送给客户端。在这种情况下,假设我使用数据注释来描述验证规则,当我将数据从域对象移动到视图模型时,视图模型不再知道它应该让接口执行什么验证(因为验证是定义在域对象上)。

使用 MVC 2,您可以让它根据当前对象的验证规则自动执行客户端/服务器端验证。但是因为验证规则是在域对象而不是视图模型上定义的,所以我必须在视图模型上复制验证规则才能使其正常工作。

其他人如何处理此类问题?我的想法是除了将域对象的数据映射到视图模型之外,我们还需要跨验证规则进行映射,但是我还没有真正看到其他人谈论这个问题...... Brad Wilson 最近谈到了这个问题长篇大论,但还没有真正解决域对象和视图模型上规则的重复问题……您的想法是什么?

干杯 安东尼

【问题讨论】:

标签: asp.net-mvc design-patterns validation viewmodel


【解决方案1】:

DataAnnotation 属性用于验证输入并向最终用户提供 UI 反馈。这确实是他们唯一的预期用途。我对 UI 对象和业务对象使用不同的验证策略,因此 DA 验证属性最终只会出现在向用户显示的模型上。

【讨论】:

  • 您好,感谢您的回复。因此,您使用 DataAnnotation 和 MVC 的能力在您的视图模型上使用它,为用户提供丰富的体验并为您的业务对象使用完全不同的策略。我假设如果验证在业务对象级别失败,您有办法将消息传回吗?另外,您如何保持验证规则同步?最后,您对业务对象使用什么样的验证框架?如果你有时间,我认为这个主题会是一篇很棒的博文……恭喜 RC。
  • 这取决于消息是什么,但大多数时候,不,我不会将消息返回给用户。您最终不得不将业务消息通过管道传回给用户的唯一情况是它是唯一可以实际验证某些内容(例如,数据库唯一性)的地方。
  • 感谢您的反馈。我真的会鼓励你写一篇关于这个主题的博客文章,因为我知道我真的会从中受益,我相信其他人也会如此。您可以列出相同的示例,其中正在验证您的 VM 以及您的业务对象以及它们是如何组合在一起的。再次感谢。
  • 抱歉挖掘了一篇旧帖子,但这最接近于清理我几天来一直在努力解决的主题(我已经阅读了关于这个主题的几篇 SO 帖子)。您能否详细说明“UI 对象和业务对象的不同验证策略”的含义?您是否总是在 UI 上而不是在域模型上执行所需的(非空)验证和字符串长度 (varchar(x)) 验证?那些讨论用 DataAnnotations 装饰域模型的讨论和博客怎么样(甚至 ScottGu 也有几个关于这方面的博客)?谢谢。
【解决方案2】:

这可能不合适,但是如果您只是将验证规则/注释从模型移到视图模型会怎样?在我参与的一些项目中,我们选择阻止 View 访问除通过其相应 ViewModel 公开的信息之外的任何内容。由于所有数据交互都将通过 ViewModel 执行,因此不需要对您的 Model 对象进行验证。

与此论点相反的是,您可以轻松复制某些验证规则,因为不同的 ViewModel 可能与相同的 Model 交互。在这种情况下,将您的模型简单地声明为在您的 ViewModel 上公开的属性可能是有意义的。对于回发,他们可以接受一个模型作为他们的参数,允许 ModelBinder 基础设施来处理请求。在这种情况下,如果 ModelState.IsValid 为 false,您可以在重新显示视图之前将属性重新分配给您的 ViewModel。

我建议将注释移至 ViewModel。这是有道理的,因为很多视图是 a) 多个模型组合的结果或 b) 模型数据的子集。

【讨论】:

    【解决方案3】:

    事实证明,AutoMapper 或许能够自动为我们完成这项工作,这是最好的情况。

    AutoMapper-users:将验证属性转移到视图模型?
    http://groups.google.com/group/automapper-users/browse_thread/thread/efa1d551e498311c/db4e7f6c93a77302?lnk=gst&q=validation#db4e7f6c93a77302

    我还没有时间尝试那里提出的解决方案,但打算很快尝试。

    (Cross 也在我的(欺骗)问题上发布了这个)。

    【讨论】:

      【解决方案4】:

      也许我们根本不应该使用视图模型? 并在模型层实体上定义验证规则..

      【讨论】:

        【解决方案5】:

        我也考虑了一段时间。我完全理解布拉德的回答。但是,假设我想使用另一个适用于注释域实体和视图模型的验证框架。

        我能在纸上提出的唯一仍然适用于属性的解决方案是创建另一个“指向”您在视图模型中镜像的域实体属性的属性。这是一个例子:

        // In UI as a view model.
        public class UserRegistration {
          [ValidationDependency<Person>(x => x.FirstName)]
          public string FirstName { get; set; }
        
          [ValidationDependency<Person>(x => x.LastName)]
          public string LastName { get; set; }
        
          [ValidationDependency<Membership>(x => x.Username)]
          public string Username { get; set; }
        
          [ValidationDependency<Membership>(x => x.Password)]
          public string Password { get; set; }
        }
        

        可以扩展像 xVal 这样的框架来处理这个新属性并在依赖类的属性上运行验证属性,但使用您的视图模型的属性值。我只是没有时间进一步充实这一点。

        有什么想法吗?

        【讨论】:

        • 至少使用建议的解决方案,您会遇到无法将 Lambda 语句放入属性的问题。这是一个不幸的限制。
        • 我喜欢这个想法,但 Chris 指出这可能行不通……我认为需要一种方法来“移植”不仅是验证定义,而且是一般的元数据。 ..但我不确定这将如何无缝融入...
        • 哦。好点。这就是为什么我应该在发布一些时间之前进行快速测试。当然,另一种选择是放弃属性注释进行验证,并使用允许您将规则(通过引用实例或列表中的名称)分配给一个或多个属性的规则引擎。也许分配可以通过属性来完成。 [ValidateWithRule("Required"), ValidateWithRule("MaxNameLength")] public string FirstName { get;放; }
        • 我一直在思考这个问题,因为它困扰了我很长时间。与注释方法保持一致,您可以“链接”域模型和视图模型之间的验证,类似于 IoC 容器或 AutoMapper 如何设置类之间的关联。这可能是您的引导代码的一部分。 ValidationMapper.Sync(x => x.FirstName).To(p => p.FirstName);
        • 假设您保持属性名称相同(如果验证是真正可映射的,您可能会这样做),那么您可以拥有指定要映射到的类的单个类级别属性。然后约定是映射任何具有相同名称的东西。使用 MVC 2,验证模型是可插拔的,因此您应该可以尝试一下。
        猜你喜欢
        • 2021-01-17
        • 1970-01-01
        • 2011-04-02
        • 2011-06-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多