CompareAttribute和比较复杂类型的属性

时间:2011-03-08 16:30:27

标签: asp.net-mvc-3 data-annotations

我刚刚阅读了MVC3的新CompareAttribute,您可以将其应用于模型的属性以定义它应该匹配的另一个属性 - 经典用例是确认电子邮件地址已正确输入,或者具有Password和ConfirmPassword字段。尝试在我自己的项目中实现它时遇到了问题。

我们有一个相当标准的User对象,除其他外,还有这些属性:

public class User {
    ....
    [Required, RegularExpression(RegularExpressions.Email, ErrorMessage = "Please supply a valid email address")]
    public string EmailAddress

    [Required]
    public string Password
    ....
}

然后我将User和我们需要的其他几个对象合并到一个视图模型中:

public class SignUpViewModel {
   ....
   public User user { get; set; }
   ....
}

当传递给UI中的表单时,允许ModelBinder在用户提交表单时为User对象以及SignUpViewModel中的其他对象和基元类型运行Data Annotation验证。当这一切“正常工作”时,我感到非常高兴,因为这意味着我们可以在一个地方定义验证,而不需要做太多的工作来坚持数据库或将UI模型映射到域模型等。

注意到Html.EditorFor(model => model.User.Password)发出的名称设置为“User.Password”,我将以下内容添加到SignUpViewModel:

[Required, Compare("User.Password")]
public string ConfirmPassword { get; set; }

但现在提交表单会触发“无法找到名为User.Password的属性”的验证错误。我希望它会遵循同样的约定,但它似乎不会:(

我真的不想将ConfirmPassword放入User对象,因为ConfirmPassword纯粹是一个UI关注点,并且在这样的域对象中使用它似乎是错误的。我也不想在SignUpViewModel中展平各种对象,因为它们开始感觉像是在定义验证规则的地方重复,我们试图尽可能地将代码保持为DRY。

有没有人遇到过让CompareAttribute与兄弟对象的属性进行比较而不是兄弟属性的方法,因为它会出现属性所期望的那样?

3 个答案:

答案 0 :(得分:2)

删除User上的SignUpViewModel媒体资源,并在User上的SignUpViewModel域对象中添加必要的媒体资源。

您说您希望将您的问题分开,并且在视图模型上将域对象作为属性是一个不将您的问题分开的示例。

这可能会导致您编写更多代码,但请查看 Automapper 等解决方案,以自动将域对象属性映射到视图模型属性。

答案 1 :(得分:1)

尽管从架构的角度来看,smartcaveman的响应很好,但它并没有解决无法在某些父模型(复杂模型)中包含的MVC3内部模型中利用CompareAttribute的客户端验证的原始问题。我知道可以从几个父容器模型中重用一些可重用的[sub]模型,并在子模型中使用CompareAttribute。 MVC3中的服务器端验证将正常工作(当客户端上禁用javascript时),但是Microsoft提供的javascript中存在一个错误,它会破坏客户端验证。请点击以下链接获取解决方案:

MVC3 CompareAttribute Client-side Bug (stackoverflow)

答案 2 :(得分:0)

我最近自己遇到了这个问题;这是我如何解决它。

true