客户端验证未针对CompareAttribute DataAnnotation触发

时间:2011-01-14 21:42:38

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

我正在布局一个比较两个密码字符串的视图。我的一个模型中的两个属性非常简单:

    [Required]
    [RegularExpression(@"(\S)+", ErrorMessage = "White space is not allowed")]
    [StringLength(20, MinimumLength = 6)]
    [DataType(DataType.Password)]
    [Display(Name = "New Password")]
    public string NewPassword { get; set; }

    [Required]
    [DataType(DataType.Password)]
    [RegularExpression(@"(\S)+", ErrorMessage = "White space is not allowed")]
    [StringLength(20, MinimumLength = 6)]
    [Display(Name = "Confirm Password")]
    [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
    public string ConfirmPassword { get; set; }

这是我的观看代码:

<table class="fieldset center" width="400">
    <tbody>
        <tr>
            <th width="150">
                @Html.LabelFor(m => m.NewPassword)
            </th>
            <td>
                @Html.PasswordFor(m => m.NewPassword, new { @class = "itext3" })
                <br /><br />@Html.ValidationMessageFor(m => m.NewPassword)
            </td>
        </tr>                       
        <tr>
            <th width="150">
                @Html.LabelFor(m => m.ConfirmPassword)
            </th>
            <td>
                @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "itext3" })
                <br /><br />@Html.ValidationMessageFor(m => m.ConfirmPassword)
            </td>
        </tr>
    </tbody>
</table>

所有属性在测试时都会触发客户端验证消息,但在ConfirmPassword上的CompareAttribute除外,直到我点击服务器才触发。但是,在我的控制器中,ModelState.IsValid = false。

我将我正在做的事情与正常工作的默认MVC应用程序进行了比较。有关故障排除和修复的建议吗?

我正在使用MVC 3 RTM。

4 个答案:

答案 0 :(得分:8)

jquery.validate.unobtrusive.js(和jquery.validate.unobtrusive.min.js,缩小版本)中有一个BUG。如果compare-to字段是表单上的FIRST字段,那么作为[Compare]属性的结果发出的客户端验证将起作用。要修复此错误,请在jquery.validate.unobtrusive.js中找到此行:

element = $(options.form).find(":input[name=" + fullOtherName + "]")[0];

导致这个等价物:

element = $(options.form).find(":input[name=MyExample.Control]")[0];

不幸的是,这不是find()的正确语法,并导致它引用表单上的第一个输入控件。

将该行更改为:

element = $(options.form).find(":input[name='" + fullOtherName + "']")[0];

导致这个等价物:

element = $(options.form).find(":input[name='MyExample.Control]'")[0];

这是正确的语法,并正确匹配输入控件与指定的名称。

在jquery.validate.unobtrusive.min.js中找到相同的代码块,如下所示:

f=a(b.form).find(":input[name="+d+"]")[0];

并将其更改为:

f=a(b.form).find(":input[name='"+d+"']")[0];

答案 1 :(得分:4)

查看_Layout.cshtml中的脚本标记。我猜这个问题可能是你的jQuery引用。您是否从头开始创建MVC 3项目,或者您正在使用示例项目或类似项目吗?

以下是我发生的事情;我有类似的问题......

  • 我在src属性中使用了一些指向ajax.microsoft.com的示例代码
  • 因此,例如,其中一个脚本标记如下所示:<script src="http://ajax.microsoft.com/ajax/jquery.validate/1.7/jquery.validate.min.js"></script>
  • 我想更好地处理js在客户端执行的操作,因此我将其更改为:<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
  • 这只是一个例子,我认为还有一些我改变的脚本标签

因此,在更改为内部提供的jQuery文件后,它工作正常。我回去查看我当地的.validate.js文件......它是版本1.6。这就是我如何意识到这个问题是由于jQuery的版本或者它与其他js libs的兼容性。

底线是看起来1.7并没有完全发挥我所拥有的validate.unobtrusive.js lib的功能......可能有一个更新的版本可以使用1.7 ...就像我说的,我是修补一个示例项目,因此有一些未知数。我想它也可能与它和其他一个js lib之间的MvcValidation.js lib不兼容?

无论如何,我要说最简单的说明问题的方法是你最有可能引用js libs的错误组合。我说最好的故障安全方法来获得js libs的良好组合是在Visual Studio中创建一个新的Asp.Net MVC 3项目并查看它默认情况下给你的版本/项目模板......这是假设的你没有从头开始项目。如果您从头开始DID,那么可能是您更改了布局文件以获得错误的js引用,或者如果这些都不是真的那么我认为它可能是VisualStudio项目模板的问题?...实际上我会说但是很可疑。所有这些 - 我说最可能的原因[无论如何我都打赌]是你遇到麻烦,就像我试图快速使用一些示例代码=)

答案 2 :(得分:1)

我用ASP.NET MVC 3 RTM对它进行了测试,它对我来说很好用:

型号:

public class MyViewModel
{
    [Required]
    [RegularExpression(@"(\S)+", ErrorMessage = "White space is not allowed")]
    [StringLength(20, MinimumLength = 6)]
    [DataType(DataType.Password)]
    [Display(Name = "New Password")]
    public string NewPassword { get; set; }

    [Required]
    [DataType(DataType.Password)]
    [RegularExpression(@"(\S)+", ErrorMessage = "White space is not allowed")]
    [StringLength(20, MinimumLength = 6)]
    [Display(Name = "Confirm Password")]
    [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
    public string ConfirmPassword { get; set; }
}

控制器:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View(new MyViewModel());
    }

    [HttpPost]
    public ActionResult Index(MyViewModel model)
    {
        return View(model);
    }
}

查看:

@model SomeAppName.Models.MyViewModel
@{
    ViewBag.Title = "Home Page";
}
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
@using (Html.BeginForm())
{
    @Html.LabelFor(m => m.NewPassword)
    @Html.PasswordFor(m => m.NewPassword)
    @Html.ValidationMessageFor(m => m.NewPassword)
    <br/>

    @Html.LabelFor(m => m.ConfirmPassword)
    @Html.PasswordFor(m => m.ConfirmPassword)
    @Html.ValidationMessageFor(m => m.ConfirmPassword)

    <br/>
    <input type="submit" value="OK" />
}

在此配置中,客户端验证对包括[Compare]

在内的所有属性完全正常

答案 3 :(得分:1)

我从未能够使用默认的工作方式。看起来像在JQuery中它只触发那些用JQuery.validator注册的验证方法。

最初我做的是这样......

jQuery.validator.unobtrusive.adapters.add("equaltopropertyvalidation", ["param"], function (rule)
    {
        alert("attaching custom validation adapter.");
        rule.rules["equaltopropertyvalidation"] = rule.params.param;
        rule.messages["equaltopropertyvalidation"] = rule.message;

        return function (value, element, param)
        {
           alert("now validating!");
           return value == this.currentForm[param].value;
        };
    });

但是我的第二个警报(现在正在验证!)即使是第一个警报也不会开火。我曾经看过this文章,但我犹豫是否要这样做,因为它需要我做一些额外的事情,但我很懒。

在花了很多时间弄清楚我的错误后,我按照本文的建议方式实施了它,并且它有效。现在它就像这样,它起作用。

<script type="text/javascript">

    jQuery.validator.addMethod("equaltopropertyvalidation", function (value, element, param)
    {
        return value == this.currentForm[param].value;
    });

    jQuery.validator.unobtrusive.adapters.add("equaltopropertyvalidation", ["param"], function (rule)
    {
        rule.rules["equaltopropertyvalidation"] = rule.params.param;
        rule.messages["equaltopropertyvalidation"] = rule.message;
    });

</script>

如果你喜欢细节,那么它是:查看jquery.validate.js并搜索

      check: function (element)

这是通过触发字段上的所有适用规则来触发以检查字段是否有效的函数。现在首先它创建一个或多个要触发的规则。它使用以下代码执行此操作。

      var rules = $(element).rules();

然后迭代规则集合,为集合中的每个项目创建规则元素,然后尝试查找为该规则触发的相应方法。一旦找到方法就会被解雇。它使用以下代码执行此操作。

      var result = $.validator.methods[method].call(this, element.value.replace(/\r/g, ""), element, rule.parameters);

现在重要的是,如果你的自定义方法没有使用JQuery.validator.addMethod添加到$ .validator.methods集合中,即使它位于JQuery.validator.unobtrusive中,也不会找到它。 .adapters集合。

可能有一种方法可以在不使用JQuery.validator.addMethod的情况下完成这项工作(如果有,那么有人请澄清)但我相信这是第二种方法有效的原因,而第一种方法并非如此。< / p>

我使用的是以下版本的Jquery文件

  1. JQuery:1.6 / 1.7.1
  2. Jquery.Validate:1.9.0
  3. JQuery.Unobtrusive.Validate:取自Microsoft CDN 2012年2月14日