这是输入屏幕不应与模型紧密耦合的根本原因。这个问题实际上每月在 MVC 标签上出现大约 3-4 次。如果我能找到上一个问题,我会欺骗,并且这里的一些评论讨论很有趣。 ;)
您遇到的问题是您试图将模型的两个不同验证上下文强制转换为单个模型,该模型在大量场景下都会失败。最好的例子是注册一个新用户,然后让管理员稍后编辑用户字段。您需要在注册期间验证用户对象的密码,但不会向编辑用户详细信息的管理员显示密码字段。
解决这些问题的选择都是次优的。我现在已经在 3 个项目中解决这个问题,并且实施以下解决方案从来都不是干净的,而且通常令人沮丧。我会尝试并成为实际的忘记其他人正在进行的所有 DDD/db/model/hotnessofthemonth 讨论。
1) 多视图模型拥有几乎相同的视图模型违反了 DRY 原则,但我觉得这种方法的成本非常低。通常,违反 DRY 会增加维护成本,但恕我直言,这样做的成本是最低的,而且金额不大。假设而言,您不会经常更改姓氏字段可以包含的最大字符数。
2)动态元数据MVC 2 中有一些钩子可以为模型提供您自己的元数据。通过这种方法,您可以根据当前的 HTTPRequest 以及 Action 和 Controller 来提供元数据,从而排除某些字段。我使用这种技术构建了一个数据库驱动的权限系统,该系统进入数据库并告诉 DataAnnotationsMetadataProvider 的子类排除数据库中存储的基于属性的值。
这项技术在 atm 上运行良好,但唯一的问题是验证UpdateModel()
。为了解决这个问题我们创建了一个SmartUpdateModel()
方法还会访问数据库并自动生成排除 string[] 数组,以便不会验证任何不允许的字段。当然,出于性能原因,我们缓存了它,所以它还不错。
只是想重申一下,我们在模型上使用了 [ValidationAttributes],然后在运行时用新规则取代了它们。最终的结果是[Required]
如果用户没有访问权限,则不会验证 User.LastName 字段。
3) 疯狂的接口动态代理我尝试的最后一种技术是使用 ViewModel 的接口。最终结果是我有一个从接口继承的 User 对象,例如IAdminEdit
and IUserRegistration
。 IAdminEdit 和 IUserRegistration 都包含 DataAnnotation 属性,这些属性执行所有上下文特定的验证,例如带有接口的密码属性。
这需要一些技巧,而且更像是一种学术练习。 2 和 3 的问题在于 UpdateModel 和 DataAnnotationsAttribute 提供程序需要进行自定义才能了解此技术。
我最大的障碍是我不想将整个用户对象发送到视图,所以我最终使用动态代理来创建运行时实例IAdminEdit
现在我明白这是一个非常 xVal 特定的问题,但是像这样的动态验证的所有途径都会导致内部 MVC 元数据提供程序的定制。由于所有元数据都是新的,目前没有什么是干净或简单的。自定义 MVC 验证行为所需要做的工作并不困难,但需要深入了解所有内部结构的工作原理。