2010-05-11 11 views
13

Come posso visualizzare gli errori ModelState restituiti da JSON?Come leggere gli errori di modelstate quando restituiti da Json?

voglio fare qualcosa di simile:

if (!ValidateLogOn(Name, currentPassword)) 
    { 
     ModelState.AddModelError("_FORM", "Username or password is incorrect."); 

     //Return a json object to the javascript 
     return Json(new { ModelState }); 
    } 

Che cosa deve essere il mio codice nella vista per leggere gli errori ModelState e visualizzarle?

Il mio codice attuale nella vista per leggere i valori JSON è la seguente:

function createCategoryComplete(e) { 
    var obj = e.get_object(); 
    alert(obj.Values); 
} 
+0

C'è una soluzione qui: http://stackoverflow.com/questions/2845852/asp-net-mvc-how-to-convert-modelstate-errors-to-json –

risposta

-8

Se si restituisce JSON, non è possibile utilizzare ModelState. Tutto ciò di cui ha bisogno la vista deve essere contenuto all'interno della stringa JSON. Così, invece di aggiungere l'errore al ModelState si potrebbe aggiungere al modello che si sta serializzazione:

public ActionResult Index() 
{ 
    return Json(new 
    { 
     errorControl = "_FORM", 
     errorMessage = "Username or password is incorrect.", 
     someOtherProperty = "some other value" 
    }); 
} 
+1

Non vedo perché ModelState non può essere usato. Per esempio.i raccoglitori di modelli possono inserire errori in ModelState, filtri di azione, ecc; se non usiamo ModelState, l'utente non ne saprà nemmeno. – queen3

+0

ModelState non serializza. Ho ottenuto un errore di riferimento circolare. –

47

Si tratta di progetto di codice, ma la stessa idea funziona per me in produzione. L'idea principale è che gli errori JSON hanno nomi di tag predefiniti, che nessun oggetto normale avrà. Per gli errori di convalida degli errori, l'HTML viene ricreato utilizzando JavaScript (sia il riepilogo superiore che l'evidenziazione degli elementi del modulo). lato

Server:

public static JsonResult JsonValidation(this ModelStateDictionary state) 
    { 
    return new JsonResult 
    { 
     Data = new 
      { 
       Tag = "ValidationError", 
       State = from e in state 
         where e.Value.Errors.Count > 0 
         select new 
         { 
         Name = e.Key, 
         Errors = e.Value.Errors.Select(x => x.ErrorMessage) 
          .Concat(e.Value.Errors.Where(x => x.Exception != null).Select(x => x.Exception.Message)) 
         } 
      } 
    }; 
    } 

    in action: 
    if (!ModelState.IsValid && Request.IsAjaxRequest()) 
     return ModelState.JsonValidation(); 

lato client:

function getValidationSummary() { 
    var el = $(".validation-summary-errors"); 
    if (el.length == 0) { 
     $(".title-separator").after("<div><ul class='validation-summary-errors ui-state-error'></ul></div>"); 
     el = $(".validation-summary-errors"); 
    } 
    return el; 
} 

function getResponseValidationObject(response) { 
    if (response && response.Tag && response.Tag == "ValidationError") 
     return response; 
    return null; 
} 

function CheckValidationErrorResponse(response, form, summaryElement) { 
    var data = getResponseValidationObject(response); 
    if (!data) return; 

    var list = summaryElement || getValidationSummary(); 
    list.html(''); 
    $.each(data.State, function(i, item) { 
     list.append("<li>" + item.Errors.join("</li><li>") + "</li>"); 
     if (form && item.Name.length > 0) 
     $(form).find("*[name='" + item.Name + "']").addClass("ui-state-error"); 
    }); 
} 

$.ajax(... function(response) { 
    CheckValidationErrorResponse(xhr.responseText); }); 
+2

Ben fatto! Anche il codice che fornisci è estremamente portatile. L'unica cosa che dovevo cambiare era "$ (". Title-separator ")" per abbinare il mio DOM. –

+0

cosa si imposta a: summaryElement ?? non lo vedo da nessuna parte nel tuo codice. – leora

+1

summaryElement viene passato a CheckValidationErrorResponse se voglio visualizzare errori nel percorso non predefinito, ad es. in forma di modifica jqGrid. Questo è un elemento/selettore jquery di ul/div/etc il cui contenuto verrà sostituito con tag li con errori. Nel mio codice sopra lo avresti passato CheckValidationErrorResponse nel callback $ .ajax. – queen3

2

questo è un piccolo tweak per il codice lato client di queen3 che gestisce i messaggi di convalida specifici, e crea un documento simile a quello creato da MVC3 :

function getValidationSummary() { 
    var $el = $(".validation-summary-errors > ul"); 
    if ($el.length == 0) { 
     $el = $("<div class='validation-summary-errors'><ul></ul></div>") 
       .hide() 
       .insertBefore('fieldset:first') 
       .find('ul'); 
    } 
    return $el; 
} 
function getResponseValidationObject(response) { 
    if (response && response.Tag && response.Tag == "ValidationError") 
     return response; 
    return null; 
} 
function isValidationErrorResponse(response, form, summaryElement) { 
    var $list, 
     data = getResponseValidationObject(response); 
    if (!data) return false; 
    $list = summaryElement || getValidationSummary(); 
    $list.html(''); 
    $.each(data.State, function (i, item) { 
     var $val, lblTxt, errorList =""; 
     if (item.Name) { 
      $val = $(".field-validation-valid,.field-validation-error") 
         .first("[data-valmsg-for=" + item.Name + "]") 
         .removeClass("field-validation-valid") 
         .addClass("field-validation-error"); 
      $("input[name=" + item.Name + "]").addClass("input-validation-error") 
      lblTxt = $("label[for=" + item.Name + "]").text(); 
      if (lblTxt) { lblTxt += ": "; } 
     } 
     if ($val.length) { 
      $val.text(item.Errors.shift()); 
      if (!item.Errors.length) { return; } 
     } 
     $.each(item.Errors, function (c,val) { 
      errorList += "<li>" + lblTxt + val + "</li>"; 
     }); 
     $list.append(errorList); 
    }); 
    if ($list.find("li:first").length) {$list.closest("div").show(); } 
    return true; 
} 
+0

Grazie Brent. Un paio di suggerimenti - $ .first() non accetta argomenti, dovrebbe essere $ .filter()? Quindi $ ("input [nome = ...]") esclude select, textarea, ecc. Potrebbe essere cambiato in $ ("* [nome = ...]")? – DGreen

1

Vedere sotto per il codice con alcuni emendamenti alla risposta di Brent. CheckValidationErrorResponse cerca il riepilogo della convalida indipendentemente dal fatto che si trovi nello stato valido o non valido e lo inserisce se non trovato. Se nella risposta si trovano errori di validazione, applica la classe validation-summary-errors al Summary, altrimenti applica validation-summary-valid. Presume che i CSS siano presenti per controllare la visibilità del Riepilogo.

Il codice cancella le istanze esistenti di errore di convalida del campo e le riapplica per gli errori rilevati nella risposta.

function getValidationSummary(form) { 
    var $summ = $(form).find('*[data-valmsg-summary="true"]'); 

    if ($summ.length == 0) 
    { 
    $summ = $('<div class="validation-summary-valid" data-valmsg-summary="true"><ul></ul></div>'); 
     $summ.appendTo(form); 
    } 

    return $summ; 
} 

function getValidationList(summary) { 
    var $list = $(summary).children('ul'); 

    if ($list.length == 0) { 
     $list = $('<ul></ul>'); 
     $list.appendTo(summary); 
    } 

    return $list; 
} 

function getResponseValidationErrors(data) { 
    if (data && data.ModelErrors && data.ModelErrors.length > 0) 
     return data.ModelErrors; 
    return null; 
} 

function CheckValidationErrorResponse(data, form, summaryElement) { 
    var errors = getResponseValidationErrors(data); 
    var $summ = summaryElement || getValidationSummary(form); 
    var $list = getValidationList($summ); 

    $list.html(''); 

    $(form).find(".field-validation-error") 
      .removeClass("field-validation-error") 
      .addClass("field-validation-valid"); 

    if (!errors) 
    { 
     $summ.removeClass('validation-summary-errors').addClass('validation-summary-valid'); 
     return false; 
    } 

    $.each(errors, function (i, item) { 
     var $val, $input, errorList = ""; 
     if (item.Name) { 
      $val = $(form).find(".field-validation-valid, .field-validation-error") 
          .filter("[data-valmsg-for=" + item.Name + "]") 
          .removeClass("field-validation-valid") 
          .addClass("field-validation-error"); 

      $input = $(form).find("*[name='" + item.Name + "']"); 

      if (!$input.is(":hidden") && !$val.length) 
      { 
       $input.parent().append("<span class='field-validation-error' data-valmsg-for='" + item.Name + "' data-valmsg-replace='false'>*</span>"); 
      } 

      $input.addClass("input-validation-error"); 
     } 

     $.each(item.Errors, function (c, err) { 
      errorList += "<li>" + err + "</li>"; 
     }); 

     $list.append(errorList); 
    }); 

    $summ.removeClass('validation-summary-valid').addClass('validation-summary-errors'); 
    return true; 
} 
3

Perché non riportare il ModelState oggetto originale al client, e quindi utilizzare jQuery per leggere i valori. A me sembra molto più semplice, e utilizza la struttura dati comune (di .net ModelState)

C#:

return Json(ModelState); 

JS:

var message = ""; 
if (e.response.length > 0) { 
    $.each(e.response, function(i, fieldItem) { 
     $.each(fieldItem.Value.Errors, function(j, errItem) { 
      message += errItem.ErrorMessage; 
     }); 
     message += "\n"; 
    }); 
    alert(message); 
} 
0

C#

public class ValidateModelAttribute : ActionFilterAttribute 
    { 
     public override void OnActionExecuting(HttpActionContext actionContext) 
     { 
      if (actionContext.ModelState.IsValid == false) 
      { 
       actionContext.Response = actionContext.Request.CreateErrorResponse(
        HttpStatusCode.BadRequest, actionContext.ModelState); 
      } 
     } 
    } 

JavaScript

$.ajax({ 
     type: "GET", 
     url: "/api/xxxxx", 
     async: 'false', 
     error: function (xhr, status, err) { 
      if (xhr.status == 400) { 
       DisplayModelStateErrors(xhr.responseJSON.ModelState); 
      } 
     }, 
.... 


function DisplayModelStateErrors(modelState) { 
    var message = ""; 
    var propStrings = Object.keys(modelState); 

    $.each(propStrings, function (i, propString) { 
     var propErrors = modelState[propString]; 
     $.each(propErrors, function (j, propError) { 
      message += propError; 
     }); 
     message += "\n"; 
    }); 

    alert(message); 
}; 
Problemi correlati