客户端验证不会针对 CompareAttribute DataAnnotation 触发

发布于 2024-10-12 06:23:48 字数 1820 浏览 3 评论 0 原文

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

    [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。

I'm laying out a view that compares two password strings. The two properties in one of my models are pretty straightforward:

    [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; }

Here's my view code:

<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>

All of the attributes fire their client-side validation messages when tested, except for the CompareAttribute on ConfirmPassword which is not firing until I hit the server. However, in my controller the ModelState.IsValid = false.

I compared what I'm doing to the default MVC application which is working correctly. Any suggestions for troubleshooting and fixing this?

I'm using MVC 3 RTM.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

零崎曲识 2024-10-19 06:23:48

jquery.validate.unobtrusive.js(和 jquery.validate.unobtrusive.min.js,缩小版本)中有一个 BUG。仅当比较字段是表单上的第一个字段时,作为 [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];

There is a BUG in jquery.validate.unobtrusive.js (and jquery.validate.unobtrusive.min.js, the minified version). The client-side validation emitted as a result of the [Compare] attribute will ONLY work if the compare-to field is the FIRST field on the form. To fix this bug, locate this line in jquery.validate.unobtrusive.js:

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

which results in this equivalent:

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

Unfortunately that's not the right syntax for find(), and causes it to reference the first input control on the form.

Change that line to:

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

which results in this equivalent:

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

Which is the correct syntax, and correctly matches the input control with the specified name.

Locate the same code block in jquery.validate.unobtrusive.min.js, which looks like this:

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

and change it to:

f=a(b.form).find(":input[name='"+d+"']")[0];
最美不过初阳 2024-10-19 06:23:48

查看 _Layout.cshtml 中的脚本标记。我猜问题可能是你的 jQuery 引用。您是从头开始 MVC 3 项目还是使用示例项目或类似项目?

这就是我身上发生的事情;我遇到了类似的问题...

  • 我正在使用一些示例代码,这些代码在 src 属性中指向 ajax.microsoft.com
  • 因此,例如其中一个脚本标签如下所示:
  • 我想更好地处理客户端执行的 js 内容所以我将其更改为:
  • 这只是一个例子,我认为我还更改了更多脚本标签,

因此,在更改为内部服务的 jQuery 文件后,它起作用了。我回去查看了本地 .validate.js 文件...它是 1.6 版本。这就是我如何意识到问题是由于 jQuery 的版本或其与其他 js 库之一的兼容性所致。

最重要的是,它看起来 1.7 不能完全与我拥有的 validate.unobtrusive.js 库一起运行...可能有一个更新的版本可以与 1.7 一起运行...就像我说的,我正在修改一个示例项目,因此存在一些未知数。我想它也可能是它与其他 js 库之一之间的 MvcValidation.js 库不兼容?

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

Take a look at your script tags in your _Layout.cshtml. I'm guessing the issue is probably your jQuery references. Did you start the MVC 3 project form scratch or are you using an example project or something like that?

Here is what happend with me; I had similar issues...

  • I was using some example code that pointed to ajax.microsoft.com in the src attributes
  • So, for example one of the script tags looked like this: <script src="http://ajax.microsoft.com/ajax/jquery.validate/1.7/jquery.validate.min.js"></script>
  • I wanted to get a better handle on what js was executing on the client side so I changed it to this: <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
  • That is just an example, I think there were a couple more script tags that I changed as well

So, after changing to internally served jQuery files it worked. I went back and looked at my local .validate.js file... and it was version 1.6. That is how i realized the issue was due to the version of jQuery or it's compatibility with one of the other the js libs anyway.

Bottom line is that it looks like 1.7 doesn't fully function with the validate.unobtrusive.js lib that I had... there may be a newer version that does function with 1.7... like I said, I was tinkering with an example project so there are some unknowns there. I suppose it could also be an incompatibility with the MvcValidation.js lib between it and one of the other js libs too?

At any rate, I'd say the simplest way to state your issue is that you are most likely referencing a bad combination of js libs. I'd say the best failsafe way to get a good combination of js libs is to create a new Asp.Net MVC 3 Project in Visual Studio and see what versions it gives you by default/with the project template... that is assuming that you didn't start the project from scratch. If you DID start it from scratch then may be you changed your layout file to have bad js references or if none of that is true then I suppose it could be a problem with the VisualStudio project templates?... realistically I'd say that is doubtful though. All of that said- I'd say the most likely cause [that I'd wager on anyway] is that you just got in trouble like me trying to quickly use some example code =)

浅忆流年 2024-10-19 06:23:48

我已经使用 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] 在内的所有属性都工作得很好。

I've tested this with ASP.NET MVC 3 RTM and it worked fine for me:

Model:

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; }
}

Controller:

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

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

View:

@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" />
}

In this configuration client side validation works perfectly fine for all attributes including the [Compare].

挥剑断情 2024-10-19 06:23:48

我始终无法采用默认的工作方式。似乎在 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;
        };
    });

但是我的第二个警报(现在正在验证!)永远不会触发,即使第一个警报会触发。我看过这篇文章但我很犹豫是否要这样实现它,因为它需要我做一些额外的事情,但我很懒。

在花了很多时间找出问题所在之后,我按照本文建议的方式实现了它并且它起作用了。现在就像这样并且有效。

<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 的情况下完成这项工作(如果是,那么请有人澄清),但我相信这是第二种方法有效而第一种方法无效的原因。

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

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

I was never able to make the default way to work. Seems like in JQuery it fires only those validation methods that are registered with JQuery.validator.

Initially I was doing something like this...

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;
        };
    });

But my second alert (now validating!) would never fire even though the first one would. I had seen this article but I was hesitating to implement it like this because it requires me to do something extra but I was lazy.

Well after spending lots of time to figure out what's wrong I implemented it in the way this article suggests and it works. Now it is like this and it works.

<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>

If you like detail then here it is: Look in jquery.validate.js and search for

      check: function (element)

This is the function that is fired to check if the field is valid or not by firing all the applicable rules on the field. Now first it creates an array or rules to fire. It does that using the following code.

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

Then it iterates over the rules collection, creates a rule element for every item in the collection and then tries to find a corresponding method to fire for that rule. Once the method is found it is fired. It does that using the following code.

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

Now the important thing is that if your custom method is not added to the $.validator.methods collection using the JQuery.validator.addMethod IT WILL NOT BE FOUND, even if it is sitting there in the JQuery.validator.unobtrusive.adapters collection.

There might be a way to make this work without using the JQuery.validator.addMethod (and if yes then someone please clarify) but this I believe is the reason the second approach works and the first doesn't.

I was using the following versions of Jquery files

  1. JQuery: 1.6/1.7.1
  2. Jquery.Validate: 1.9.0
  3. JQuery.Unobtrusive.Validate: taken from Microsoft CDN on
    2/14/2012.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文