【问题标题】:ASP.NET MVC Ajax submit form with AntiforgeryToken and Serialized Form data with ValidationASP.NET MVC Ajax 提交带有 AntiforgeryToken 的表单和带有验证的序列化表单数据
【发布时间】:2018-08-25 11:03:59
【问题描述】:

我正在尝试通过这样的 ajax 提交表单:

$(document).ready(function () {
        $("#form").submit(function (e) {
            e.preventDefault();
            var token = $('input[name="__RequestVerificationToken"]', this).val();
            var form_data = $(this).serialize();
            $.ajax({
                url: "@Url.Action("SaveRole", @ViewContext.RouteData.Values["controller"].ToString())",
                method: "POST",
                data: form_data,
                contentType: "application/json",
                success: function (result) {
                    console.log(result);
                },
                error: function (error) {
                    console.log(error);
                }
            });
            return false;
            console.log(form_data);
        });
    });

这会联系这个控制器:

    [HttpPost]
    [ValidateAjax]
    [ValidateAntiForgeryToken]
    public ActionResult SaveRole(SaveRolesDetailsViewModel Input)
    {
        //var role = rolesData.GetByName(Input);
        var result = this.Json(new
        {
            Output = Input
        }, JsonRequestBehavior.DenyGet);
        return result;
    }

现在,我收到我的 RequestVerificationToken 字段未提交的错误,但我不确定如何将它与我的表单数据结合起来。默认情况下,当我序列化表单数据时,它已经发送了这个令牌,但由于某种原因我的控制器仍然失败。

另外,我如何使用模型状态来显示我的表单验证?现在它们作为 json 对象返回。

编辑:

AjaxValidate 属性:

public class ValidateAjax : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (!filterContext.HttpContext.Request.IsAjaxRequest())
                return;

            var modelState = filterContext.Controller.ViewData.ModelState;
            if (!modelState.IsValid)
            {
                var errorModel =
                        from x in modelState.Keys
                        where modelState[x].Errors.Count > 0
                        select new
                        {
                            key = x,
                            errors = modelState[x].Errors.
                            Select(y => y.ErrorMessage).
                            ToArray()
                        };
                filterContext.Result = new JsonResult()
                {
                    Data = errorModel
                };
                filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
            }
        }
    }

当我提交一个空表单时,返回的内容如下:

0:{key: "RoleName", errors: ["The Role Name field is required."]}

【问题讨论】:

    标签: javascript jquery asp.net asp.net-mvc


    【解决方案1】:

    当你使用 jQuery .serialize() 方法时,它会生成查询字符串格式(即..&name=value&...,需要使用默认的contentType 发送 - 即'application/x-www-form-urlencoded; charset=UTF-8'

    从 ajax 选项中删除 contentType: "application/json",

    此外,您的var token = $('input[name="__RequestVerificationToken"]', this).val(); 代码行不是必需的 - 使用.serialize() 时包含令牌

    $("#form").submit(function (e) {
        e.preventDefault();
        // Add the following if you have enabled client side validation
        if (!$(this).valid()) {
            return;
        }
        var form_data = $(this).serialize();
        $.ajax({
            url: "@Url.Action("SaveRole")",
            method: "POST",
            data: form_data,
            success: function (result) {
                ... // see notes below
            },
            error: function (error) {
                console.log(error);
            }
        });
        // return false; not necessary since you have used e.preventDefault()
        console.log(form_data);
    });
    

    要返回ModelState 错误,请删除您的ValidateAjaxAttribute - 返回BadRequest 是不合适的(其目的是表明服务器由于语法无效而无法理解请求) .

    改为修改 POST 方法以返回包含错误的JsonResult(注意不需要返回模型)

    public ActionResult SaveRole(SaveRolesDetailsViewModel Input)
    {
        if (ModelState.IsValid)
        {
            return Json(new { success = true });
        }
        else
        {
            var errors = ModelState.Keys.Where(k => ModelState[k].Errors.Count > 0).Select(k => new { propertyName = k, errorMessage = ModelState[k].Errors[0].ErrorMessage });
            return Json(new { success = false, errors = errors });
        }
    }
    

    然后在成功回调中,如果有错误,循环遍历,找到你的@Html.ValidationMessageFor()生成的对应的<span>元素,更新其内容和类名

    success: function (result) {
        if (result.success) {
            return;
        }
        $.each(result.errors, function(index, item) {
            // Get message placeholder
            var element = $('[data-valmsg-for="' + item.propertyName + '"]');
            // Update message
            element.append($('<span></span>').text(item.errorMessage));
            // Update class names
            element.removeClass('field-validation-valid').addClass('field-validation-error');
            $('#' + item.propertyName).removeClass('valid').addClass('input-validation-error');
        });
    },
    

    【讨论】:

    • 至于ModelState 错误,您需要说明如何在 POST 方法中返回该数据
    • 嘿,谢谢!我将编辑问题以包含返回 ajax 验证问题的方法。
    • 你的方法没有返回 ModelState 错误(它只是返回你的模型)。而且您不应该仅仅因为ModelState 无效而返回BadRequest
    • 嗨,如果我只使用像 ModelState.valid 这样的东西就足够了吗?是的,消息占位符是由@Html.ValidationMessageFor(m=>m.property) 生成的。感谢您的帮助。
    • 会试一试。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-22
    • 2011-07-09
    • 2013-02-09
    • 1970-01-01
    • 2018-06-30
    • 2015-03-27
    • 2014-09-15
    相关资源
    最近更新 更多