Sử dụng xác thực ASP.NET MVC với jquery ajax?


119

Tôi có hành động ASP.NET MVC đơn giản như sau:

public ActionResult Edit(EditPostViewModel data)
{

}

EditPostViewModelcác thuộc tính xác thực như sau:

[Display(Name = "...", Description = "...")]
[StringLength(100, MinimumLength = 3, ErrorMessage = "...")]
[Required()]
public string Title { get; set; }

Trong chế độ xem, tôi đang sử dụng các trình trợ giúp sau:

 @Html.LabelFor(Model => Model.EditPostViewModel.Title, true)

 @Html.TextBoxFor(Model => Model.EditPostViewModel.Title, 
                        new { @class = "tb1", @Style = "width:400px;" })

Nếu tôi gửi trên một biểu mẫu mà hộp văn bản này được đặt trong xác nhận sẽ được thực hiện trước tiên trên máy khách và sau đó trên dịch vụ ( ModelState.IsValid).

Bây giờ tôi có một vài câu hỏi:

  1. Điều này có thể được sử dụng với jQuery ajax submit thay thế không? Những gì tôi đang làm chỉ đơn giản là xóa biểu mẫu và khi nhấp vào nút gửi, javascript sẽ thu thập dữ liệu và sau đó chạy $.ajax.

  2. Phía máy chủ sẽ ModelState.IsValidhoạt động?

  3. Làm cách nào để tôi có thể chuyển tiếp vấn đề xác thực trở lại máy khách và trình bày nó như thể tôi đang sử dụng xây dựng int validation ( @Html.ValidationSummary(true))?

Ví dụ về lệnh gọi Ajax:

function SendPost(actionPath) {
    $.ajax({
        url: actionPath,
        type: 'POST',
        dataType: 'json',
        data:
        {
            Text: $('#EditPostViewModel_Text').val(),
            Title: $('#EditPostViewModel_Title').val() 
        },
        success: function (data) {
            alert('success');
        },
        error: function () {
            alert('error');
        }
    });
}

Chỉnh sửa 1:

Bao gồm trên trang:

<script src="/Scripts/jquery-1.7.1.min.js"></script>
<script src="/Scripts/jquery.validate.min.js"></script>
<script src="/Scripts/jquery.validate.unobtrusive.min.js"></script>

Câu trả lời rất hay dưới đây. Đây là một câu hỏi liên quan. Câu trả lời cho phép xác thực phía máy khách hoặc phía máy chủ. Tôi thích mã JQuery mà họ cung cấp. (Không, đó không phải là câu trả lời của tôi.) Stackoverflow.com/questions/28987752/…
Adventure

Câu trả lời:


155

Phía khách hàng

Sử dụng jQuery.validatethư viện phải khá đơn giản để thiết lập.

Chỉ định các cài đặt sau trong Web.configtệp của bạn :

<appSettings>
    <add key="ClientValidationEnabled" value="true"/> 
    <add key="UnobtrusiveJavaScriptEnabled" value="true"/> 
</appSettings>

Khi bạn xây dựng chế độ xem của mình, bạn sẽ xác định những thứ như sau:

@Html.LabelFor(Model => Model.EditPostViewModel.Title, true)
@Html.TextBoxFor(Model => Model.EditPostViewModel.Title, 
                                new { @class = "tb1", @Style = "width:400px;" })
@Html.ValidationMessageFor(Model => Model.EditPostViewModel.Title)

LƯU Ý: Chúng cần được xác định trong phần tử biểu mẫu

Sau đó, bạn sẽ cần bao gồm các thư viện sau:

<script src='@Url.Content("~/Scripts/jquery.validate.js")' type='text/javascript'></script>
<script src='@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")' type='text/javascript'></script>

Điều này sẽ có thể giúp bạn thiết lập xác thực phía máy khách

Tài nguyên

Phía máy chủ

LƯU Ý: Điều này chỉ dành cho xác thực phía máy chủ bổ sung trên đầu jQuery.validationthư viện

Có lẽ một cái gì đó như thế này có thể giúp:

[ValidateAjax]
public JsonResult Edit(EditPostViewModel data)
{
    //Save data
    return Json(new { Success = true } );
}

Trong trường hợp ValidateAjaxlà một thuộc tính định nghĩa là:

public class ValidateAjaxAttribute : 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;
        }
    }
}

Điều này làm là trả về một đối tượng JSON chỉ định tất cả các lỗi mô hình của bạn.

Câu trả lời ví dụ sẽ là

[{
    "key":"Name",
    "errors":["The Name field is required."]
},
{
    "key":"Description",
    "errors":["The Description field is required."]
}]

Điều này sẽ được trả lại cho việc xử lý lỗi của bạn gọi lại $.ajaxcuộc gọi

Bạn có thể lặp lại dữ liệu trả về để đặt các thông báo lỗi khi cần thiết dựa trên các Phím được trả về (Tôi nghĩ rằng điều gì đó giống như $('input[name="' + err.key + '"]')sẽ tìm thấy phần tử đầu vào của bạn


1
Câu trả lời tuyệt vời, đặc biệt là với ValidateAjaxAttribute tuyệt vời! Cảm ơn bạn!
René

3
Tôi không hiểu tại sao câu trả lời này lại nhận được nhiều phiếu bầu như vậy. Nó không trả lời câu hỏi 1: làm thế nào để xác thực khách hàng khi đăng bài với $ .ajax? Tôi nghĩ câu trả lời @Shyju sẽ giúp được điều đó.
Valentin ngày

2
@Valentin - câu trả lời của tôi thực sự hữu ích vì dữ liệu cũng được xác thực từ phía máy chủ. Các plugin xác thực phải cho phép xác thực động khi biểu mẫu được điền và khi biểu mẫu được gửi (tuy nhiên OP muốn làm điều đó), máy chủ sẽ cung cấp xác thực cuối cùng, điều này luôn thích hợp vì có thể bỏ qua xác thực phía máy khách.
Andrew Burgess,

8
Tôi sử dụng các khoảng thời gian thông báo xác thực của jQuery bằng cách lặp lại các lỗi được trả về và chèn thông báo lỗi vào đúng khoảng thời gian:for (var i = 0; i < modelStateErrors.length; i++) { $('span[data-valmsg-for="' + modelStateErrors[i].key + '"]').text(modelStateErrors[i].errors[0]); }
Ian

7
Câu trả lời này là tuyệt vời! Nhưng tôi vẫn nghĩ rằng khung ASP.NET MVC nên cung cấp một cách tích hợp để làm điều đó.
Zignd

40

Những gì bạn nên làm là tuần tự hóa dữ liệu biểu mẫu của bạn và gửi nó đến hành động của bộ điều khiển. ASP.NET MVC sẽ liên kết dữ liệu biểu mẫu vớiEditPostViewModel đối tượng (tham số phương thức hành động của bạn), sử dụng tính năng ràng buộc mô hình MVC.

Bạn có thể xác thực biểu mẫu của mình ở phía máy khách và nếu mọi thứ đều ổn, hãy gửi dữ liệu đến máy chủ. Các valid()phương pháp sẽ có ích.

$(function () {

    $("#yourSubmitButtonID").click(function (e) {

        e.preventDefault();
        var _this = $(this);
        var _form = _this.closest("form");

        var isvalid = _form .valid();  // Tells whether the form is valid

        if (isvalid)
        {           
           $.post(_form.attr("action"), _form.serialize(), function (data) {
              //check the result and do whatever you want
           })
        }

    });

});

1
Cảm ơn! Tôi đã thử $ ("form #" + formId) .validate () này nhưng nó nói rằng biểu mẫu (được tìm thấy) không có validate ()?
Ivy

Xem Edit1 nơi tôi cho thấy rằng tập lệnh xác thực được bao gồm trên trang web. Tôi cũng thấy rằng xác thực đang chạy khi sử dụng nút gửi loại đầu vào thông thường.
Ivy

Tôi đã tìm thấy sự cố (đã xóa Scripts.Render khỏi trang chủ). Nhưng vẫn có vấn đề để gửi lại lỗi xác thực ModelState cho máy khách? Tôi làm thế nào để giải quyết vấn đề đó? Ví dụ: nếu người dùng không đăng nhập nữa (ModelState.AddModelError ("CustomError", "văn bản xác thực").
Ivy

1
bạn cần bao gồm các tệp jquery.validate và jquery.validate.unobtrilities js trong trang của mình. Đầu vào HTML của bạn có thuộc tính mà plugin xác thực tìm kiếm không?
Shyju

1
Ivy: Kiểu trả về của bạn (ActionResult) là một lớp cơ sở của JsonResult. vì vậy nó có thể trả về dữ liệu JSON. Những gì bạn nên làm là, Nếu đó là một cuộc gọi ajax (kiểm tra Request.IsAjax), hãy lấy các lỗi xác thực và xây dựng một JSON và gửi lại cho máy khách. Kiểm tra json trong phương thức gọi lại của $ .post và hiển thị thông báo lỗi.
Shyju 29/12/12

9

Đây là một giải pháp khá đơn giản:

Trong bộ điều khiển, chúng tôi trả về các lỗi như sau:

if (!ModelState.IsValid)
        {
            return Json(new { success = false, errors = ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage).ToList() }, JsonRequestBehavior.AllowGet);
        }

Đây là một số tập lệnh ứng dụng khách:

function displayValidationErrors(errors)
{
    var $ul = $('div.validation-summary-valid.text-danger > ul');

    $ul.empty();
    $.each(errors, function (idx, errorMessage) {
        $ul.append('<li>' + errorMessage + '</li>');
    });
}

Đó là cách chúng tôi xử lý nó thông qua ajax:

$.ajax({
    cache: false,
    async: true,
    type: "POST",
    url: form.attr('action'),
    data: form.serialize(),
    success: function (data) {
        var isSuccessful = (data['success']);

        if (isSuccessful) {
            $('#partial-container-steps').html(data['view']);
            initializePage();
        }
        else {
            var errors = data['errors'];

            displayValidationErrors(errors);
        }
    }
});

Ngoài ra, tôi hiển thị các chế độ xem từng phần qua ajax theo cách sau:

var view = this.RenderRazorViewToString(partialUrl, viewModel);
        return Json(new { success = true, view }, JsonRequestBehavior.AllowGet);

Phương thức RenderRazorViewToString:

public string RenderRazorViewToString(string viewName, object model)
    {
        ViewData.Model = model;
        using (var sw = new StringWriter())
        {
            var viewResult = ViewEngines.Engines.FindPartialView(ControllerContext,
                                                                     viewName);
            var viewContext = new ViewContext(ControllerContext, viewResult.View,
                                         ViewData, TempData, sw);
            viewResult.View.Render(viewContext, sw);
            viewResult.ViewEngine.ReleaseView(ControllerContext, viewResult.View);
            return sw.GetStringBuilder().ToString();
        }
    }

3
"GetModelStateErrors" của bạn có thể được đơn giản hóa hoàn toàn bằng cách chuyển đổi nó thành một câu lệnh một dòng đơn giản hơn: return ModelState.Values.SelectMany (x => x.Errors) .Select (x => x.ErrorMessage) .ToList ();
Camilo Terevinto

1
Tại sao không chỉ đơn giản là trả về một PartialViewđể hiển thị cho Ajax?
Sinjai

4

Đã thêm một số logic khác vào giải pháp do @Andrew Burgess cung cấp. Đây là giải pháp đầy đủ:

Đã tạo bộ lọc hành động để nhận lỗi cho yêu cầu ajax:

public class ValidateAjaxAttribute : 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;
            }
        }
    }

Đã thêm bộ lọc vào phương thức bộ điều khiển của tôi dưới dạng:

[HttpPost]
// this line is important
[ValidateAjax]
public ActionResult AddUpdateData(MyModel model)
{
    return Json(new { status = (result == 1 ? true : false), message = message }, JsonRequestBehavior.AllowGet);
}

Đã thêm một tập lệnh chung để xác thực jquery:

function onAjaxFormError(data) {
    var form = this;
    var errorResponse = data.responseJSON;
    $.each(errorResponse, function (index, value) {
        // Element highlight
        var element = $(form).find('#' + value.key);
        element = element[0];
        highLightError(element, 'input-validation-error');

        // Error message
        var validationMessageElement = $('span[data-valmsg-for="' + value.key + '"]');
        validationMessageElement.removeClass('field-validation-valid');
        validationMessageElement.addClass('field-validation-error');
        validationMessageElement.text(value.errors[0]);
    });
}

$.validator.setDefaults({
            ignore: [],
            highlight: highLightError,
            unhighlight: unhighlightError
        });

var highLightError = function(element, errorClass) {
    element = $(element);
    element.addClass(errorClass);
}

var unhighLightError = function(element, errorClass) {
    element = $(element);
    element.removeClass(errorClass);
}

Cuối cùng đã thêm phương thức javascript lỗi vào biểu mẫu Ajax Begin của tôi:

@model My.Model.MyModel
@using (Ajax.BeginForm("AddUpdateData", "Home", new AjaxOptions { HttpMethod = "POST", OnFailure="onAjaxFormError" }))
{
}

1

Bạn có thể làm theo cách này:

( Chỉnh sửa: Xem xét rằng bạn đang chờ phản hồi jsonvới dataType: 'json')

.MẠNG LƯỚI

public JsonResult Edit(EditPostViewModel data)
{
    if(ModelState.IsValid) 
    {
       // Save  
       return Json(new { Ok = true } );
    }

    return Json(new { Ok = false } );
}

JS:

success: function (data) {
    if (data.Ok) {
      alert('success');
    }
    else {
      alert('problem');
    }
},

Nếu bạn cần, tôi cũng có thể giải thích cách thực hiện bằng cách trả về lỗi 500 và nhận lỗi trong lỗi sự kiện (ajax). Nhưng trong trường hợp của bạn, đây có thể là một lựa chọn


1
Tôi biết cách thực hiện yêu cầu Jason thông thường, tuy nhiên, điều này sẽ không giúp tôi xác thực các thuộc tính khác nhau hoặc thậm chí sử dụng Xác thực ASP.NET MVC tích hợp sẵn mà tôi đã yêu cầu. Tôi có thể có thể xây dựng một đối tượng Jason phức tạp để giải thích các lỗi xác thực cho mọi đối tượng thích hợp nhưng điều này sẽ không hiệu quả và tôi hy vọng rằng bạn có thể sử dụng lại chức năng được tích hợp sẵn của xác thực ASP.NET MVC cho việc này?
Ivy

1 - Làm cách nào để chạy chức năng "SendPost" ?, và 2 - dữ liệu hợp lệ của bạn trên máy khách?
andres descalzo

Xin giải thích? Không nhận được bài viết cuối cùng của bạn?
Ivy
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.