ASP.NET MVC Ajax отправляет форму с данными AntiforgeryToken и сериализованной формы с проверкой - PullRequest
0 голосов
/ 25 августа 2018

Я пытаюсь отправить форму через 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.

EDIT:

Атрибут 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."]}

1 Ответ

0 голосов
/ 25 августа 2018

Когда вы используете метод jQuery .serialize(), он генерирует формат строки запроса (т.е. ..&name=value&..., который необходимо отправить с использованием значения по умолчанию contentType - т.е. 'application/x-www-form-urlencoded; charset=UTF-8'.

Удалите contentType: "application/json", из параметров ajax.

Кроме того, ваша строка кода 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 });
    }
}

Затем в обратном вызове успеха, если есть ошибки, переберите их и найдите соответствующий элемент <span>, сгенерированный вашим @Html.ValidationMessageFor(), и обновите его содержимое и имена классов

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');
    });
},
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...