ASP.NET-MVC jQuery 不显眼的远程验证返回误报

Posted

技术标签:

【中文标题】ASP.NET-MVC jQuery 不显眼的远程验证返回误报【英文标题】:ASP.NET-MVC jQuery unobtrusive remote validation returns false positives 【发布时间】:2014-05-29 04:08:54 【问题描述】:

我回到了一个我在 9 个月前工作的项目,查看我们编写的一些代码,希望现在有更好的方法来做到这一点......

虽然最初对 jQuery 的不显眼的验证印象深刻,但我们最终不得不将下面的 hack 组合在一起(部分基于我现在无法动手的博客文章)来处理远程验证。问题是服务器端验证过程很慢 - 通常是任何涉及数据库调用的事情 - 验证器不会等待来自验证方法的响应,并且会表现得好像它已经回传了一个肯定的。

黑客基本上是继续检查验证器是否有任何待处理的请求,直到它没有,当你可以确定一个真实的验证结果时才继续:

function SaveChangePassword() 

// Find form, fire validation
var $form = $("#btnSave").closest("form");

if ($form.valid()) 
//Do nothing - just firing validation


// Calls method every 30 milliseconds until remote validation is complete
var interval = setInterval(saveWhenValidationComplete, 30);

// Check if validation pending, save and clear interval if not
function saveWhenValidationComplete() 

    // Find form validator, check if validation pending - save once remote validation is finished
    var validator = $form.data("validator");
    if (validator.pendingRequest === 0) 

        clearInterval(interval);

        //Force validation to present to user (this will not retrigger remote validation)
        if ($form.valid()) 

            var closeButton = "<br/><input type='button' value='OK' style='font-size:small; font-weight:bold; float:right;' onclick=\"$('#changePasswordDialog').dialog('close');\" class='greenbutton' />";
            // If form is valid then submit
            $.ajax(
                
                    type: "POST",
                    url: "/Account/SavePassword",
                    data: $form.serialize(),
                    success: function (result) 
                        var successMessage = "<div style='text-align:center; margin-top: 10px;'>" + result + "<div>";
                        $("#changePasswordDialog").html(successMessage + closeButton);
                            ,
                    error: function (jqXhr, textStatus, errorThrown) 
                        // Populate dialog with error message and button
                        var errorMessage = "<div style='text-align:center'>Error '" + jqXhr.status + "' (Status: '" + textStatus + "', errorThrown: '" + errorThrown + "')<div>";
                        $("#changePasswordDialog").html(errorMessage + closeButton);
                    
                );

        

        // Else validation will show
    

    // Else don't save yet, wait another 30 miliseconds while validation runs
;

// Prevent default and stop event propagation
return false;

我希望在过去的 9 个月中出现了一些进展,而这不再是必要的了!欢迎任何想法,让我知道是否可以提供更多详细信息。

【问题讨论】:

我认为你应该做更多的挖掘来发现这个问题的根源。多年来,我一直在 MVC 中使用不显眼的验证,从未遇到过您所描述的问题。 你使用远程属性提交ajax表单了吗?这是 100% 的问题,我已经调试并看到了各种问题,只是希望有一些进展,因为它看起来有点令人震惊。 是的,我有。我想我可能明白这里发生了什么。 [Remote] 属性应该在值更改后立即引起客户端验证,以便向用户提供即时反馈。但是,验证是异步的,因此是非阻塞的。与 all 客户端验证一样,它可以为用户提供更即时、一致的反馈,并且您仍然需要在服务器端执行相同的检查。如果你这样做了,那么表单发布将产生与[Remote] 属性在提交之前返回的结果相同的结果。无需破解。 所以你是说重用验证方法来检查值并且只插入/更新/如果有效,那么验证消息一旦从服务器返回就会显示?我理解正确吗?这实际上不是一个坏主意 是的,我稍后会添加一些代码作为答案。 【参考方案1】:

虽然您可以为用户提供客户端验证,但您应该始终(始终!)在服务器上重新验证。用户很容易禁用 javascript 或以其他方式伪造无效的 POST 到您的控制器操作,如果您不检查服务器端的内容,您就会为用户创造机会破坏您系统中的数据。

幸运的是,ASP.NET MVC 中的大多数验证都已经为您完成了。如果您的控制器操作如下所示:

public ActionResult SaveSomething(Something thing)

    if(!ModelState.IsValid)
    
        return View("EditSomething", thing);
    
    // otherwise, save something...

...那么您将发现用户提供的值无法绑定到您的数据属性的问题,以及由[Required][StringLength(x)] 等属性验证的内容。但是,某些形式的验证不会自动为您检查。 [Remote] 就是其中之一。

如果你有一个[Remote] 属性指向这样的控制器操作:

public ActionResult CheckThingCodeValidity(string code)

    return Json(_thingCodeChecker.ThingCodeWorks(code), JsonRequestBehavior.AllowGet);

...那么您的提交操作中也应该有类似的内容:

public ActionResult SaveSomething(Something thing)

    if(!_thingCodeChecker.ThingCodeWorks(thing.Code))
    
        ModelState.AddModelError("Code", "This code is not valid.");
    
    if(!ModelState.IsValid)
    
        return View("EditSomething", thing);
    
    // otherwise, save something...

这样,您的标准服务器端验证技术可以将视图发送回用户,并在该属性上向他们提供错误消息,以指示他们需要修复的内容。

如果您这样做,那么您不必担心在提交表单时是否仍在进行异步验证检查。如果您的客户端验证通常由于缺陷、网络问题或恶意用户干预而失败,这并不重要。您仍然会阻止他们提交无效的内容,并且他们仍然会得到一个很好的视图,告诉他们为什么他们的提交无效。

【讨论】:

只是想说我终于开始重构并使用此方法并且效果很好,非常感谢您提供的示例。 这确实不能回答问题。客户端验证的全部目的不是让用户在失败时不必将整个表单提交到服务器进行验证吗?希望不显眼的验证在远程验证完成之前不允许提交表单似乎很合理,但是这个答案对这个问题没有帮助。 @JohnWasham:客户端验证的重点是尽快给用户反馈。如果我填写完表单并在远程验证往返返回之前点击“提交”,我宁愿让表单立即发送数据,而不是让客户端挂起以期待找出服务器是否可能接受。如果远程验证失败,我会尽快找到。但如果它成功了,那么它会更快地成功。 @StriplingWarrior,我明白你的意思了。我想我正在看它的方式,我正在做的客户端远程验证应该返回亚秒级或接近,所以实际上并没有用户等待的想法。在这种情况下,让表单无效直到远程验证返回输入的“是”或“否”是有道理的,这就是原始问题的真正含义。一直在寻找,仍然没有找到答案。 @StriplingWarrior,我可能只是想错了。我的表单只是其他人用来使用远程验证来验证输入的一个元素,所以我在那个盒子里思考。但是就像您说的那样,提交带有潜在错误数据的表单所花费的时间可能与等待远程验证完成,然后提交表单所花费的时间大致相同。所以现在我正在跟踪你的想法。谢谢。

以上是关于ASP.NET-MVC jQuery 不显眼的远程验证返回误报的主要内容,如果未能解决你的问题,请参考以下文章

在 asp.net-mvc 中,在不影响其他用户的情况下进行昂贵操作的正确方法是啥?

asp.net-mvc:js文件中的剃刀'@'符号

代码执行速度:ASP.NET-MVC与PHP

有人愤怒地使用带有 asp.net-mvc 的 Knockoutjs 吗? [关闭]

剑道 DropDownListFor() 与 ASP.NET-MVC

ASP.NET-MVC5 - 为啥 Bootstrap v4 主题不能正确显示组件?