Jquery ajax ile ASP.NET MVC doğrulaması kullanılsın mı?


119

Bunun gibi basit ASP.NET MVC eylemim var:

public ActionResult Edit(EditPostViewModel data)
{

}

Aşağıdaki EditPostViewModelgibi doğrulama özniteliklerine sahiptir:

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

Görünümde aşağıdaki yardımcıları kullanıyorum:

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

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

Bir formda bu metin kutusunun bir doğrulamaya yerleştirildiğine dair bir gönderim yaparsam, önce istemcide ve sonra hizmette ( ModelState.IsValid) yapılır.

Şimdi birkaç sorum var:

  1. Bunun yerine jQuery ajax gönderimi ile kullanılabilir mi? Yaptığım şey basitçe formu kaldırmak ve gönder düğmesine tıkladığınızda bir javascript verileri toplayacak ve ardından $.ajax.

  2. Sunucu tarafı ModelState.IsValidçalışacak mı?

  3. Doğrulama problemini istemciye nasıl iletebilirim ve bunu build int validation ( @Html.ValidationSummary(true)) kullanıyormuş gibi sunabilirim ?

Ajax çağrısı örneği:

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

Düzenleme 1:

Sayfaya dahil:

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

Aşağıda güzel cevap. İşte ilgili bir soru. Cevap, istemci tarafı veya sunucu tarafı doğrulamaya izin verir. Sağladıkları JQuery koduna aşığım. (Hayır, cevabım değildi.) Stackoverflow.com/questions/28987752/…
Macera

Yanıtlar:


155

İstemci Tarafı

jQuery.validateKütüphaneyi kullanmak, kurmak oldukça basit olmalıdır.

Web.configDosyanızda aşağıdaki ayarları belirtin :

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

Görüşünüzü oluşturduğunuzda, aşağıdaki gibi şeyleri tanımlarsınız:

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

NOT: Bunların bir form öğesi içinde tanımlanması gerekir

O zaman aşağıdaki kitaplıkları eklemeniz gerekir:

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

Bu sizi istemci tarafı doğrulama için ayarlayabilmelidir

kaynaklar

Sunucu Tarafı

NOT: Bu yalnızca jQuery.validationkitaplığın üstünde ek sunucu tarafı doğrulama içindir.

Belki bunun gibi bir şey yardımcı olabilir:

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

ValidateAjaxBir öznitelik nerede tanımlanır:

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

Bunun yaptığı şey, tüm model hatalarınızı belirten bir JSON nesnesi döndürmektir.

Örnek yanıt şöyle olacaktır:

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

Bu, $.ajaxaramanın hata işleme geri aramasına döndürülür.

Döndürülen Anahtarlara göre hata mesajlarını gerektiği gibi ayarlamak için döndürülen veriler arasında döngü yapabilirsiniz (sanırım $('input[name="' + err.key + '"]')giriş öğenizi


1
Özellikle harika ValidateAjaxAttribute ile harika yanıt! Teşekkür ederim!
René

3
Bu cevabın neden bu kadar çok oy aldığını anlamıyorum. 1. soruya cevap vermiyor: $ .ajax ile gönderi yaparken müşteri doğrulaması nasıl yapılır? @Shyju yanıtının buna yardımcı olduğunu düşünüyorum.
Valentin

2
@Valentin - Cevabım yardımcı oluyor çünkü veriler sunucu tarafında da doğrulanıyor. Doğrulama eklentileri, form doldurulurken dinamik doğrulamayı etkinleştirmelidir ve form gönderildiğinde (ancak OP bunu yapmak ister), sunucu nihai doğrulamayı sağlayacaktır; bu, istemci tarafında doğrulama atlanabileceğinden her durumda tercih edilir.
Andrew Burgess

8
JQuery'nin doğrulama mesajını, döndürülen hatalar arasında döngü yaparak ve hata mesajını doğru aralığa ekleyerek kullanıyorum:for (var i = 0; i < modelStateErrors.length; i++) { $('span[data-valmsg-for="' + modelStateErrors[i].key + '"]').text(modelStateErrors[i].errors[0]); }
Ian

7
Bu cevap harika! Ancak yine de ASP.NET MVC çerçevesinin bunu yapmak için yerleşik bir yol sağlaması gerektiğini düşünüyorum.
Zignd

40

Yapmanız gereken, form verilerinizi seri hale getirmek ve denetleyici eylemine göndermektir. ASP.NET MVC, EditPostViewModelMVC model bağlama özelliğini kullanarak form verilerini nesneye (eylem yöntemi parametreniz) bağlar.

Formunuzu istemci tarafında doğrulayabilir ve her şey yolundaysa verileri sunucuya gönderebilirsiniz. valid()Yöntem kullanışlı olacaktır.

$(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
Teşekkürler! Bu $ ("form #" + formId) .validate () denedim, ancak formun (bulunan) bir validate () içermediğini söylüyor?
Ivy

Doğrulama komut dosyasının web sayfasına dahil edildiğini gösterdiğim Düzenleme1'e bakın. Ayrıca, normal giriş türü gönderme düğmesi kullanıldığında doğrulamanın çalıştığını görüyorum.
Ivy

Sorunu buldum (Scripts.Render'ı ana sayfadan kaldırdım). Ancak yine de ModelState doğrulama hatalarını istemciye geri göndermekte sorun mu yaşıyorsunuz? Bunu nasıl halledebilirim? Örneğin, kullanıcı artık oturum açmadıysa (ModelState.AddModelError ("CustomError", "doğrulama metni").
Ivy

1
jquery.validate ve jquery.validate.unobtrusive js dosyalarını sayfanıza eklemeniz gerekir. HTML girişleriniz, doğrulama eklentilerinin aradığı özelliğe sahip mi?
Shyju

1
Ivy: Dönüş türünüz (ActionResult), JsonResult'un temel sınıfıdır. böylece JSON verilerini döndürebilir. Yapmanız gereken şey, eğer bu bir ajax çağrısıysa (Request.IsAjax'ı kontrol edin), doğrulama hatalarını alın ve bir JSON oluşturun ve istemciye geri gönderin. $ .Post'un geri arama yönteminde json'u kontrol edin ve hata mesajlarını gösterin.
Shyju

9

İşte oldukça basit bir çözüm:

Denetleyicide hataları şöyle döndürüyoruz:

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

İstemci komut dosyasından bazıları:

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

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

Ajax aracılığıyla bu şekilde başa çıkıyoruz:

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

Ayrıca, kısmi görünümleri ajax aracılığıyla şu şekilde işliyorum:

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

RenderRazorViewToString yöntemi:

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", daha basit bir tek satırlık ifadeye dönüştürülerek tamamen basitleştirilebilir: ModelState.Values.SelectMany (x => x.Errors) .Select (x => x.ErrorMessage) .ToList ();
Camilo Terevinto

1
Neden PartialViewrender etmek için Ajax'a geri dönmüyorsunuz ?
Sinjai

4

@Andrew Burgess tarafından sağlanan çözüme biraz daha mantık eklendi. İşte tam çözüm:

Ajax isteği için hataları almak için bir eylem filtresi oluşturuldu:

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

Filtreyi denetleyici yöntemime şu şekilde ekledim:

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

Jquery doğrulaması için ortak bir komut dosyası eklendi:

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

Son olarak, Ajax Begin formuma hata javascript yöntemini ekledim:

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

1

Bunu şu şekilde yapabilirsiniz:

( Düzenleme: Eğer bir yanıt bekliyoruz düşünüldüğünde jsonile dataType: 'json')

.AĞ

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

İhtiyacınız olursa, 500 hatası döndürerek nasıl yapılacağını da açıklayabilir ve olay hatası (ajax) içindeki hatayı alabilirim. Ama senin durumunda bu bir seçenek olabilir


1
Normal bir Jason isteğinin nasıl yapılacağını biliyorum, ancak bu bana farklı özelliklerin doğrulanmasında yardımcı olmayacak ve hatta istediğim yerleşik ASP.NET MVC Doğrulamasını kullanmayacaktır. Muhtemelen her özellik için doğrulama hatalarını açıklamak için karmaşık bir Jason nesnesi oluşturabilirim, ancak bu çok iş olacak ve bunun için ASP.NET MVC doğrulamasının yerleşik işlevselliğini yeniden kullanabileceğinizi umuyorum?
Ivy

1 - "SendPost" işlevinizi nasıl çalıştırırsınız? Ve 2 - istemcideki geçerli verileriniz?
andres descalzo

Lütfen açıklamak mı? Son gönderinizi almadınız mı?
Ivy
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.