Как читать ошибки состояния модели, когда возвращается Json? - PullRequest
14 голосов
/ 11 мая 2010

Как я могу отобразить ошибки 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); 
} 

Ответы [ 6 ]

48 голосов
/ 11 мая 2010

Это черновик кода, но та же самая идея работает для меня в производстве. Основная идея здесь заключается в том, что у ошибок Json есть предопределенные имена тегов, которых нет у обычных объектов. Для ошибок проверки ошибок HTML заново создается с использованием JavaScript (как с подсветкой верхней сводки, так и элементов формы).

Серверная сторона:

  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); } );
3 голосов
/ 20 сентября 2013

Почему бы не вернуть исходный объект ModelState клиенту, а затем использовать jQuery для чтения значений. Для меня это выглядит намного проще и использует общую структуру данных (.net's ModelState)

C #:

return Json(ModelState);

ЯШ:

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);
}
2 голосов
/ 29 августа 2012

это крошечная настройка клиентского кода 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;
}
1 голос
/ 24 мая 2013

См. Ниже код с несколькими поправками к ответу Брента. CheckValidationErrorResponse ищет сводную информацию о проверке независимо от того, находится ли она в действительном или недействительном состоянии, и вставляет ее, если она не найдена. Если в ответе обнаружены ошибки проверки, он применяет класс validation-summary-errors к Summary, иначе он применяет 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;
}
0 голосов
/ 06 сентября 2016

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);
};
0 голосов
/ 11 мая 2010

Если вы возвращаете JSON, вы не можете использовать ModelState. Все, что нужно для представления, должно содержаться в строке JSON. Поэтому вместо добавления ошибки в ModelState вы можете добавить ее в сериализованную модель:

public ActionResult Index()
{
    return Json(new 
    {
        errorControl = "_FORM",
        errorMessage = "Username or password is incorrect.",
        someOtherProperty = "some other value"
    });
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...