2010-05-11 38 views
13

如何顯示JSON返回的ModelState錯誤?如何在Json返回時讀取模型狀態錯誤?

我想要做這樣的事情:

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

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

什麼一定是我的視圖代碼讀取的ModelState錯誤,並顯示它們?

我在視圖中實際的代碼讀取JSON值如下:

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

這裏有一個解決方案:http://stackoverflow.com/questions/2845852/asp-net-mvc-how-to-convert-modelstate-errors-to-json – 2012-11-22 15:26:40

回答

-8

如果你正在返回JSON,你不能使用的ModelState。視圖需要的所有東西都應該包含在JSON字符串中。因此,而不是將錯誤的ModelState中,你可以把它添加到您的序列化的模型:

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

不明白爲什麼ModelState不能使用。例如。模型粘合劑可以將錯誤放入模型狀態,動作過濾器等​​;如果我們不使用ModelState,用戶甚至不會知道它們。 – queen3 2010-05-11 08:01:32

+0

ModelState不會序列化。我收到了循環引用錯誤。 – 2014-02-04 10:44:01

47

這是準則草案,但同樣的想法在生產中對我的作品。 這裏的主要想法是Json錯誤有預定義的標籤名稱,沒有普通的對象會有。對於錯誤驗證錯誤使用JavaScript重新創建HTML(高亮總結和表單元素高亮顯示)。

服務器端:

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

客戶端:

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

做得很好!您提供的代碼也非常便於攜帶。我唯一需要改變的是「$(」。title-separator「)」來匹配我的DOM。 – 2010-12-08 00:53:52

+0

你會做什麼:summaryElement ??我沒有看到你的代碼中的任何地方。 – leora 2011-04-20 05:40:41

+1

summary如果我想在非默認位置顯示錯誤,則將元素傳遞給CheckValidationErrorResponse - 例如在jqGrid編輯表單中。這是一個ul/div/etc的jquery元素/選擇器,其內容將被替換爲帶有錯誤的li標籤。在我上面的代碼中,您可以在$ .ajax回調中傳遞CheckValidationErrorResponse。 – queen3 2011-05-17 07:18:44

2

這是一個很小的調整,以queen3的客戶端代碼處理特定的驗證消息,並創建一個類似的文件,以通過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

謝謝布倫特。幾個建議 - $ .first()不接受參數,它應該是$ .filter()嗎?然後$(「input [name = ...]」)排除select,textarea等 - 可以更改爲$(「* [name = ...]」)? – DGreen 2013-05-24 11:05:29

1

請參閱下面的代碼,對布倫特答案進行一些修改。 CheckValidationErrorResponse查找驗證摘要,無論其處於有效還是無效狀態,並在未找到時插入。如果在響應中發現驗證錯誤,它將validation-summary-errors類應用於摘要,否則它將應用validation-summary-valid。它假定CSS存在以控制摘要的可見性。

該代碼清除現有的field-validation-error實例,並重新應用它們以查找響應中發現的錯誤。

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

爲什麼不將原始ModelState對象返回給客戶端,然後使用jQuery讀取值。對我來說,它看起來更簡單,並採用通用的數據結構(.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); 
};