当我开始使用 XVAL 获得客户端验证,我只是执行的动作方法,其用于域模型对象作为一个视图模型或视图模型的那些对象的嵌入实例。

本办法正常工作的大部分时间,但是当视图需要显示,当用户想要更新自己的密码,回来后只有模型的属性的子集(例如有这样的情况,但不其余他配置文件数据)。

一(丑陋)的解决方法是具有形式为不另外存在窗体上的每个属性上的隐藏的输入字段。

显然这里最好的做法是创建一个定制视图模型仅包含有关视图属性和经由填充视图模型Automapper 。这是干净多了,因为我只传输数据相关的观点,但它远非完美,因为我要重复已经存在的域模型对象相同的验证属性。

理想情况下,我想指定域模型对象作为经由元数据属性的元类(这也常常被称为“伙伴类”),但是,这并不工作,因为XVAL抛出当元数据类有属性不存在的视图模型。

是否有任何优雅的解决方法呢?我一直在考虑的黑客攻击源代码XVAL,但或许是迄今为止我忽略了一些其他的方式。

谢谢,

阿德里安

修改。通过ASP.NET MVC 2的到来,这不仅关系到验证属性的问题了,但它也适用于编辑和显示属性。

有帮助吗?

解决方案

这是典型的原因的输入屏幕不应被紧密耦合到模型。这个问题实际上在MVC标签这里会弹出一个每月3-4次。我想欺骗,如果我能找到以前的问题,这里的一些评论的讨论很有意思。 ;)

您遇到的问题是你想迫使模型的两个不同的验证环境在其中大量的场景下失败的单一模式。最好的例子是注册一个新用户,然后有一个管理员后编辑用户领域。你需要验证注册过程中用户对象上的密码,但你不会在密码领域展现给管理员编辑用户的详细信息。

为围绕这些获得的选择都是次优的。现在我已经在这个问题上工作了3个项目,并实施了以下解决方案从来没有干净,通常令人沮丧。我要去尝试和实际并忘记所有的DDD / DB /模型/ hotnessofthemonth讨论别人都拥有。

<强> 1)的多视图模型  具有几乎相同违反了DRY主要的ViewModels但我觉得这种方法的成本也相当低廉。通常违反干安培了维护成本但恕我直言这样做的成本是最低的,并没有什么了不起的。假如说你不改变姓氏字段可数最多如何人物有非常频繁。

<强> 2)的动态元数据 有在MVC 2挂钩的模型提供自己的元数据。通过这种方法,你可以拥有任何你使用提供的元数据排除基于当前的HTTPRequest,因此行动和控制器的某些字段。我用这个技术来建立一个数据库驱动的权限系统都到数据库,并告诉了DataAnnotationsMetadataProvider的子类,以排除基于存储在数据库中值的属性。

此技术工作很大大气压但唯一的问题与UpdateModel()验证。为了解决这个问题,我们创建了一个SmartUpdateModel()方法,该方法还进到数据库并自动生成排除串[]数组,以使任何非permissisable字段不验证。我们当然这个缓存性能方面的原因所以它不坏。

只是想重申,我们使用[ValidationAttributes]在我们的模型,然后用运行时新的规则superceeded他们。最终的结果是,如果用户不具有权限访问它的[Required] User.LastName字段未通过验证。

第3)疯狂接口动态代理事 最后一个技术我想是使用接口来的ViewModels。最终的结果是我不得不从像IAdminEditIUserRegistration接口继承的用户对象。 IAdminEdit和IUserRegistration既能包含执行的所有上下文中的具体验证像与接口Password属性DataAnnotation属性。

这需要一些两轮牛车,是更大的学术活动,比什么都重要。 2和3的问题是,的UpdateModel和DataAnnotationsAttribute提供商需要进行定制,以进行意识到这种技术的。

我的最大的绊脚石是我没有想整个用户发送对象的观点,所以我结束了使用动态代理创建IAdminEdit的运行情况

现在我明白这是一个非常具体的XVAL问题,但所有的道路,这样导致内部MVC元数据提供商定制动态验证。由于所有的元数据的东西是什么新的是,清洗或简单的在这一点上做的。这项工作你不得不做定制MVC的验证行为并不难,但在一些需要深入的了解如何将所有的内部工作。

其他提示

我们移动我们的验证属性视图模型层。在我们的例子中,这个反正提供的担忧清晰分离,因为那时我们能够设计我们的域模型,使得其不能进入无效状态摆在首位。例如,日期可能需要一个BillingTransaction对象。所以,我们不想让它空。但在我们的视图模型,我们可能需要公开可空,使得我们能赶上在用户没有输入值的情况。

在其他情况下,你可能有验证即每页/形式具体,你要根据用户所要进行的,而不是设置一堆东西,并要求域模型的命令来验证, “你有效尝试做XYZ”,这里做“ABC”的值是有效的。

如果是的ViewModels假设被迫在你身上,那么我建议他们只执行领域无关的要求。这包括诸如“用户名是必需的”和“电子邮件格式正确”。

如果你从视图模型的域模型重复验证,那么你就紧密耦合域到用户界面。当域验证的变化(“只能每星期敷2优惠券”变成了“只可申请每周1张优惠券”),用户界面必须更新。一般而言,这将是可怕的,并且有害的敏捷性。

如果您从域模型移动验证的用户界面,你已经基本上烧毁您的域名,并放在验证UI上的责任。第二UI会重复所有的验证,并且您已经连接的两个独立的UI的一起。现在,如果客户需要一个特殊的接口,从他们的iPhone管理库存,iPhone的项目需要复制所有也在网站UI中进行验证。 这甚至会比上述验证复制更可怕。

除非你能预测未来,并能排除这些可能性,只验证域无关的要求。

我不知道这将如何为客户端验证发挥,但如果部分验证是你的问题,你可以修改这里讨论采取属性名称的DataAnnotationsValidationRunner列表IEnumerable<string>,如下:

public static class DataAnnotationsValidationRunner
{
     public static IEnumerable<ErrorInfo> GetErrors(object instance, IEnumerable<string> fieldsToValidate)
     {
           return from prop in TypeDescriptor.GetProperties(instance).Cast<PropertyDescriptor>().Where(p => fieldsToValidate.Contains(p.Name))
                  from attribute in prop.Attributes.OfType<ValidationAttribute>()
                  where !attribute.IsValid(prop.GetValue(instance))
                  select new ErrorInfo(prop.Name, attribute.FormatErrorMessage(string.Empty), instance);
     }
}

我要风险downvotes和状态,有到的ViewModels没有好处(在ASP.NET MVC),尤其是考虑创建和维护他们的开销。如果这个想法是由域脱钩,这是站不住脚的。从域中分离的UI是不是那个域的UI。该UI的必须的依赖于域,所以你要么将不得不连接到域模型的意见/行动,或连接到域模型视图模型的管理逻辑。架构参数因此是没有实际意义。

如果这个想法是防止用户黑客称取ASP.NET MVC的模型的优点结合到突变字段它们不应被允许改变,则A)的域应该执行这个要求恶意HTTP的POST,和B)的行动应提供可更新的特性的白名单到模型粘合剂。

除非你域暴露出一些疯狂喜欢活在内存中的对象图,而不是实体副本的ViewModels是无用功。因此,要回答你的问题,保持域验证的域模型。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top