Json返回时如何读取modelstate错误?

发布于 2024-09-01 01:13:21 字数 504 浏览 2 评论 0原文

如何显示 JSON 返回的 ModelState 错误?

我想做这样的事情:

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

How can I display ModelState errors returned by JSON?

I want to do something like this:

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

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

What must be my code in the view to read the ModelState errors and display them?

My actual code in the view to read the JSON values is as follows:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

时光沙漏 2024-09-08 01:13:21

这是代码草案,但同样的想法在生产中也适用于我。
这里的主要思想是 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); } );

This is draft code but the same idea works for me in production.
The main idea here is that Json errors have predefined tag names, that no normal objects will have. For errors validation errors HTML is re-created using JavaScript (both top summary and form elements highlighting).

Server side:

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

Client side:

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); } );
独自←快乐 2024-09-08 01:13:21

为什么不将原始的 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);
}

Why not return the original ModelState object to the client, and then use jQuery to read the values. To me it looks much simpler, and uses the common data structure (.net's 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);
}
天荒地未老 2024-09-08 01:13:21

这是对 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;
}

this is a tiny tweak to queen3's client side code which handles specific validation messages, and creates a similar document to that created by 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;
}
青瓷清茶倾城歌 2024-09-08 01:13:21

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

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);
};
↘紸啶 2024-09-08 01:13:21

请参阅下面的代码,并对布伦特的答案进行了一些修改。 CheckValidationErrorResponse 会查找验证摘要,无论其处于有效还是无效状态,如果未找到,则将其插入。如果在响应中发现验证错误,则会将validation-summary-errors类应用于摘要,否则它将应用validation-summary-valid。它假设 CSS 存在来控制摘要的可见性。

该代码清除现有的字段验证错误实例,并对响应中发现的错误重新应用它们。

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

See below for code with a few amendments to Brent's answer. CheckValidationErrorResponse looks for the Validation Summary regardless of whether it's in the valid or invalid state, and inserts it if not found. If validation errors are found in the response, it applies the validation-summary-errors class to the Summary, else it applies validation-summary-valid. It assumes CSS is present to control the visibility of the Summary.

The code clears existing instances of field-validation-error, and reapplies them for errors found in the response.

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;
}
迷雾森÷林ヴ 2024-09-08 01:13:21

如果返回 JSON,则无法使用 ModelState。视图所需的所有内容都应包含在 JSON 字符串内。因此,您可以将错误添加到正在序列化的模型中,而不是将错误添加到 ModelState 中:

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

If you are returning JSON, you cannot use ModelState. Everything that the view needs should be contained inside the JSON string. So instead of adding the error to the ModelState you could add it to the model you are serializing:

public ActionResult Index()
{
    return Json(new 
    {
        errorControl = "_FORM",
        errorMessage = "Username or password is incorrect.",
        someOtherProperty = "some other value"
    });
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文