在自定义 ViewModel 中重用验证属性 [英] Reusing validation attributes in custom ViewModels

查看:27
本文介绍了在自定义 ViewModel 中重用验证属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我开始使用 xVal 进行客户端验证时,我只是在实现使用域模型的操作方法对象作为视图模型或这些对象在视图模型中的嵌入实例.

When I started using xVal for client-side validation, I was only implementing action methods which used domain model objects as a viewmodel or embedded instances of those objects in the viewmodel.

这种方法在大多数情况下都可以正常工作,但在某些情况下,视图只需要显示和回发模型属性的一个子集(例如,当用户想要更新他的密码,而不是他的其余部分时)个人资料数据).

This approach works fine most of the time, but there are cases when the view needs to display and post back only a subset of the model's properties (for example when the user wants to update his password, but not the rest of his profile data).

一个(丑陋的)解决方法是在表单上为每个不存在于表单上的属性设置一个隐藏的输入字段.

One (ugly) workaround is to have a hidden input field on the form for each property that is not otherwise present on the form.

显然这里的最佳实践是创建一个自定义视图模型,它只包含与视图相关的属性,并通过 填充视图模型自动映射器.它更清晰,因为我只传输与视图相关的数据,但它远非完美,因为我必须重复域模型对象上已经存在的相同验证属性.

Apparently the best practice here is to create a custom viewmodel which only contains properties relevant to the view and populate the viewmodel via Automapper. It's much cleaner since I am only transferring the data relevant to the view, but it's far from perfect since I have to repeat the same validation attributes that are already present on the domain model object.

理想情况下,我想通过 MetaData 属性将域模型对象指定为元类(这通常也称为伙伴类"),但这不起作用,因为当元数据类具有时 xVal 抛出视图模型上不存在的属性.

Ideally I'd like to specify the Domain Model object as a meta class via a MetaData attribute (this is also often referred to as "buddy class"), but that doesn't work since xVal throws when the metadata class has properties that are not present on the viewmodel.

有什么优雅的解决方法吗?我一直在考虑破解 xVal 源代码,但也许到目前为止我还忽略了其他一些方法.

Is there any elegant workaround to this? I've been considering hacking the xVal sourcecode, but perhaps there is some other way I have overlooked so far.

谢谢,

阿德里安

随着 ASP.NET MVC 2 的到来,这不仅是与验证属性相关的问题,而且还适用于编辑器和显示属性.

With the arrival of ASP.NET MVC 2, this is not only a problem related to validation attributes anymore, but it also applies to editor and display attributes.

推荐答案

这就是为什么您的输入屏幕不应与您的模型紧密耦合的典型原因.这个问题实际上每月在 MVC 标签上出现大约 3-4 次.如果我能找到上一个问题和这里的一些评论讨论很有趣,我会被骗.;)

This is the quintessential reason why your input screens should not be tightly coupled to your model. This question actually pops up here on the MVC tag about 3-4 times a month. I'd dupe if I could find the previous question and some of the comment discussion here is interesting. ;)

您遇到的问题是您试图将一个模型的两个不同验证上下文强制转换为一个模型,该模型在大量场景下失败.最好的例子是注册一个新用户,然后让管理员稍后编辑用户字段.您需要在注册期间验证用户对象的密码,但不会向编辑用户详细信息的管理员显示密码字段.

The issue your having is you're trying to force two different validation contexts of a model into a single model which fails under a large amount of scenarios. The best example is signing up a new user and then having an admin edit a user field later. You need to validate a password on a user object during registration but you won't show the password field to the admin editing the user details.

解决这些问题的选择都是次优的.我现在已经为 3 个项目解决了这个问题,并且实施以下解决方案从来都不是干净的,而且通常令人沮丧.我将尝试实际,忘记所有其他人正在讨论的所有 DDD/db/model/hotnessofthemonth 讨论.

The choices for getting around these are all sub-optimal. I've worked on this problem for 3 projects now and implementing the following solutions has never been clean and usually frustrating. I'm going to try and be practical and forget all the DDD/db/model/hotnessofthemonth discussions everybody else is having.

1) 多视图模型拥有几乎相同的视图模型违反了 DRY 原则,但我觉得这种方法的成本非常低.通常违反 DRY 放大器会增加维护成本,但恕我直言,这方面的成本是最低的,并不多.假设您不会经常更改姓氏字段的最大字符数.

1) Multiple View Models Having viewmodels that are almost the same violates the DRY principal but I feel the costs of this approach are really low. Usually violating DRY amps up maintenance costs but IMHO the costs for this are the lowest and don't amount to much. Hypothetically speaking you don't change how max number characters the LastName field can have very often.

2) 动态元数据MVC 2 中有一些钩子可以为模型提供您自己的元数据.使用这种方法,您可以使用任何用于提供元数据的方式排除某些基于当前 HTTPRequest 的字段,因此也可以排除 Action 和 Controller.我已经使用这种技术构建了一个数据库驱动的权限系统,该系统进入数据库并告诉 DataAnnotationsMetadataProvider 的子类排除存储在数据库中的基于属性的值.

2) Dynamic Metadata There are hooks in MVC 2 for providing your own metadata for a model. With this approach you could have whatever your using to provide metadata exclude certain fields based on the current HTTPRequest and therefore Action and Controller. I've used this technique to build a database driven permissions system which goes to the DB and tells the a subclass of the DataAnnotationsMetadataProvider to exclude properties based values stored in the database.

这项技术在 atm 中运行良好,但唯一的问题是使用 UpdateModel() 进行验证.为了解决这个问题,我们创建了一个 SmartUpdateModel() 方法,该方法也转到数据库并自动生成排除 string[] 数组,以便不验证任何不允许的字段.我们当然出于性能原因缓存了它,所以它不错.

This technique is working great atm but the only problem is validating with UpdateModel(). To solve this problem we created a SmartUpdateModel() method which also goes to the database and automatically generates the exclude string[] array so that any non-permissisable fields aren't validated. We of course cached this for performance reasons so its not bad.

只想重申,我们在模型上使用了 [ValidationAttributes],然后在运行时用新规则取代了它们.最终结果是,如果用户没有访问权限,[Required] User.LastName 字段将不会被验证.

Just want to reiterate that we used [ValidationAttributes] on our models and then superceeded them with new rules on runtime. The end result was that the [Required] User.LastName field wasn't validated if the user didn't have permission to access it.

3) 疯狂的界面动态代理我尝试使用的最后一种技术是为 ViewModel 使用接口.最终结果是我有一个继承自 IAdminEditIUserRegistration 等接口的 User 对象.IAdminEdit 和 IUserRegistration 都包含 DataAnnotation 属性,这些属性执行所有上下文特定的验证,如带有接口的 Password 属性.

3) Crazy Interface Dynamic Proxy Thing The last technique I tried to was to use interfaces for ViewModels. The end result was I had a User object that inherited from interfaces like IAdminEdit and IUserRegistration. IAdminEdit and IUserRegistration would both contain DataAnnotation attributes that performed all the context specific validation like a Password property with the interfaces.

这需要一些技巧,而且比其他任何事情都更像是一种学术练习.问题 2 和 3 的问题在于,需要自定义 UpdateModel 和 DataAnnotationsAttribute 提供程序才能了解此技术.

This required some hackery and was more an academic exercise than anything else. The problem with 2 and 3 is that UpdateModel and the DataAnnotationsAttribute provider needed to be customized to be made aware of this technique.

我最大的绊脚石是我不想将整个用户对象发送到视图,所以我最终使用动态代理来创建 IAdminEdit

My biggest stumbling block was I didn't ever want to send the whole user object to the view so I ended up using dynamic proxies to create runtime instances of IAdminEdit

现在我明白这是一个非常特定于 xVal 的问题,但是像这样的动态验证的所有途径都会导致内部 MVC 元数据提供程序的定制.由于所有元数据都是新的,在这一点上没有什么是干净或简单的.自定义 MVC 验证行为所需的工作并不难,但需要深入了解所有内部机制的工作原理.

Now I understand this is a very xVal specific question but all of the roads to dynamic validation like this lead to customization of the internal MVC Metadata providers. Since all the metadata stuff is new nothing is that clean or simple to do at this point. The work you'd have to do to customize MVC's validation behavior isn't hard but requires some in depth knowledge of how all of the internals work.

这篇关于在自定义 ViewModel 中重用验证属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆