![]() |
1
7
这就是为什么输入屏幕不应该与模型紧密耦合的典型原因。这个问题实际上是在MVC标签上出现的,大约一个月3-4次。如果我能找到前面的问题,并且这里的一些评论讨论是有趣的,我会重复的。;) 您所面临的问题是,您试图将一个模型的两个不同的验证上下文强制为一个在大量场景下失败的模型。最好的例子是注册一个新用户,然后让管理员稍后编辑一个用户字段。您需要在注册期间验证用户对象的密码,但不会向管理员显示密码字段,编辑用户详细信息。 绕过这些的选择都是次优的。我现在已经为3个项目处理了这个问题,并且实现以下解决方案从来都不是干净的,通常是令人沮丧的。我会努力做到 实际的 忘记所有其他人正在进行的第几个讨论中的ddd/db/model/hotness。 1)多视图模型 拥有几乎相同的视图模型违反了干法原理,但我觉得这种方法的成本非常低。通常违反了干安培的维护成本,但在我看来,这是最低的成本,并不算多。假设您不会经常更改姓氏字段的最大字符数。 2)动态元数据 MVC 2中有一些钩子,用于为模型提供您自己的元数据。使用这种方法,您可以使用任何方法来提供元数据,根据当前的httpRequest排除某些字段,从而排除操作和控制器。我使用这种技术构建了一个数据库驱动的权限系统,该系统指向数据库,并告诉DataAnnotationsMetadataProvider的子类排除数据库中存储的基于属性的值。
这项技术在ATM上很有效,但唯一的问题是用
只是想重申一下,我们在模型上使用了[validationattributes],然后在运行时用新的规则对它们进行了替换。最终结果是
3)疯狂界面动态代理
我尝试的最后一种技术是为视图模型使用接口。最终的结果是我有一个用户对象继承自
这需要一些黑客,而且更像是一种学术活动。2和3的问题在于,需要对updateModel和dataAnnotationsAttribute提供程序进行定制以了解此技术。
我最大的障碍是我不想将整个用户对象发送到视图,所以我最终使用动态代理来创建
现在我明白这是一个非常XVAL特定的问题,但是像这样的动态验证的所有道路都会导致内部MVC元数据提供程序的定制。因为所有的元数据都是新的,所以在这一点上没有什么是干净的或简单的。要定制MVC的验证行为,您需要做的工作并不困难,但需要一些深入了解所有内部工作原理的知识。 |
![]() |
2
4
我们将验证属性移到了ViewModel层。在我们的例子中,无论如何,这提供了一个更清晰的关注分离,因为我们当时能够设计我们的域模型,这样它就不会在一开始就进入无效状态。例如,BillingTransaction对象可能需要日期。所以我们不想让它可以为空。但是在我们的viewModel中,我们可能需要公开nullable,这样我们就可以捕捉到用户没有输入值的情况。 在其他情况下,您可能有特定于每一页/表单的验证,并且您希望根据用户试图执行的命令进行验证,而不是设置一堆东西并询问域模型,“您尝试执行xyz是否有效”,在执行“abc”时,这些值是有效的。 |
![]() |
3
3
如果假设视图模型是强制的,那么我建议它们只强制执行不可知域的需求。这包括“需要用户名”和“电子邮件格式正确”等内容。 如果您从视图模型中的域模型中复制验证,那么您已经将域与UI紧密耦合。当域验证更改时(“每周只能应用2张优惠券”变为“每周只能应用1张优惠券”),必须更新UI。一般来说,这是可怕的,对敏捷性有害。 如果您将验证从域模型移动到UI,那么实际上您已经删除了您的域,并将验证的责任放到了UI上。第二个UI必须复制所有验证,并且您已经将两个独立的UI耦合在一起。现在,如果客户想要一个特殊的界面来管理他们iPhone的库存,iPhone项目需要复制网站用户界面中的所有验证。 这将比上面描述的验证复制更糟糕。 除非您能够预测未来并排除这些可能性,否则只能验证领域不可知的需求。 |
![]() |
4
2
我不知道这对于客户端验证有什么作用,但是如果部分验证是您的问题,您可以修改
|
![]() |
5
0
我将冒着被否决的风险,声明视图模型(在ASP.NET MVC中)没有好处,特别是考虑到创建和维护它们的开销。如果这个想法是要与领域脱钩,那是不可辩驳的。与域分离的UI不是该域的UI。用户界面 必须 取决于域,所以您要么将视图/操作耦合到域模型,要么将视图模型管理逻辑耦合到域模型。因此,架构的争论是没有意义的。 如果目的是防止用户利用ASP.NET MVC的模型绑定对可变字段进行黑客攻击,则不允许更改这些字段,那么a)域应强制执行此要求,b)操作应向模型绑定器提供可更新属性的白名单。 除非你所在的域公开了一些疯狂的东西,比如一个动态的内存对象图,而不是实体副本,否则视图模型是浪费精力的。因此,要回答您的问题,请在域模型中保留域验证。 |