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