ASP.NET MVC ModelState 오류를 json으로 변환하는 방법


127

모든 ModelState 오류 메시지 목록을 어떻게 얻습니까? 모든 키를 얻기 위해이 코드를 찾았습니다. ( ModelState 오류가있는 키 목록 반환 )

var errorKeys = (from item in ModelState
        where item.Value.Errors.Any() 
        select item.Key).ToList();

그러나 오류 메시지를 IList 또는 IQueryable로 어떻게 얻을 수 있습니까?

나는 갈 수 있었다 :

foreach (var key in errorKeys)
{
    string msg = ModelState[error].Errors[0].ErrorMessage;
    errorList.Add(msg);
}

그러나 그것은 수동으로하는 것입니다-확실히 LINQ를 사용하는 방법이 있습니까? .ErrorMessage 속성은 지금까지 체인에 있으므로 LINQ를 작성하는 방법을 모르겠습니다 ...

답변:


192

당신은 넣을 수 있습니다 아무것도 당신이 내부에 원하는 select절을 :

var errorList = (from item in ModelState
        where item.Value.Errors.Any() 
        select item.Value.Errors[0].ErrorMessage).ToList();

편집 : 다음 from과 같은 절 을 추가하여 여러 오류를 별도의 목록 항목으로 추출 할 수 있습니다 .

var errorList = (from item in ModelState.Values
        from error in item.Errors
        select error.ErrorMessage).ToList();

또는:

var errorList = ModelState.Values.SelectMany(m => m.Errors)
                                 .Select(e => e.ErrorMessage)
                                 .ToList();

2 편집 : 당신이 찾고있는 Dictionary<string, string[]>:

var errorList = ModelState.ToDictionary(
    kvp => kvp.Key,
    kvp => kvp.Value.Errors.Select(e => e.ErrorMessage).ToArray()
);

빠른 답변 :)! 이봐, 좋아 보이지만 ModelState [item.Key]에 둘 이상의 오류가 있으면 어떻게합니까? 오류 [0]은 단일 오류 메시지
JK에

그것들을 어떻게 결합하고 싶습니까?
SLaks

거의 고마워하지만 오류가 없어도 모든 키를 선택하면 오류없이 키를 어떻게 필터링 할 수 있습니까?
JK.

4
추가.Where(kvp => kvp.Value.Errors.Count > 0)
SLaks

3
같은 출력을 얻으려면 다음 Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);을 사용해야합니다. var errorList = modelState.Where(elem => elem.Value.Errors.Any()) .ToDictionary( kvp => kvp.Key, kvp => kvp.Value.Errors.Select(e => string.IsNullOrEmpty(e.ErrorMessage) ? e.Exception.Message : e.ErrorMessage).ToArray());그렇지 않으면 ExceptionMessages가 없습니다.
Silvos

74

다음은 모든 부분을 종합 한 전체 구현입니다.

먼저 확장 메소드를 작성하십시오.

public static class ModelStateHelper
{
    public static IEnumerable Errors(this ModelStateDictionary modelState)
    {
        if (!modelState.IsValid)
        {
            return modelState.ToDictionary(kvp => kvp.Key,
                kvp => kvp.Value.Errors
                                .Select(e => e.ErrorMessage).ToArray())
                                .Where(m => m.Value.Any());
        }
        return null;
    }
}

그런 다음 해당 확장 메소드를 호출하고 컨트롤러 조치 (있는 경우)에서 오류를 json으로 리턴하십시오.

if (!ModelState.IsValid)
{
    return Json(new { Errors = ModelState.Errors() }, JsonRequestBehavior.AllowGet);
}

마지막으로 클라이언트 측에서 오류를 표시하십시오 (jquery.validation 스타일이지만 다른 스타일로 쉽게 변경할 수 있음)

function DisplayErrors(errors) {
    for (var i = 0; i < errors.length; i++) {
        $("<label for='" + errors[i].Key + "' class='error'></label>")
        .html(errors[i].Value[0]).appendTo($("input#" + errors[i].Key).parent());
    }
}

이것은 흥미로운 방법처럼 보이지만 도우미 클래스는 나를 위해 작동하지 않습니다. MVC 2의 변경 때문일까요? ToDictionary 메소드가 modelState에 존재하지 않는다는 오류가 발생합니다.
Cymen

@Cymen System.Linq를 참조하는 것을 잊고 있습니까? ToDictionary ()는 LINQ 확장 메서드입니다.
Nathan Taylor

8
귀하의 환경 설정에 따라 .Where(m => m.Value.Count() > 0)이라고도 쓸 수 있습니다 .Where(m => m.Value.Any()).
Manfred

Kendo.Mvc의 ModelState.ToDataSourceResult ()와 유사하게 그리드에 오류를 반환하고 편집시 오류 메시지를 표시 할 수 있습니다.
malnosna

22

Hashtable문자열 배열 형태의 속성으로 키와 오류가있는 JSON 객체를 값으로 얻을 수 있도록 여기에서 사용 하고 싶습니다.

var errors = new Hashtable();
foreach (var pair in ModelState)
{
    if (pair.Value.Errors.Count > 0)
    {
        errors[pair.Key] = pair.Value.Errors.Select(error => error.ErrorMessage).ToList();
    }
}
return Json(new { success = false, errors });

이렇게하면 다음과 같은 응답을 얻을 수 있습니다.

{
   "success":false,
   "errors":{
      "Phone":[
         "The Phone field is required."
      ]
   }
}

8

이 작업을 수행하는 방법에는 여러 가지가 있습니다. 여기 내가 지금 해요 ...

if (ModelState.IsValid)
{
    return Json("Success");
}
else
{
    return Json(ModelState.Values.SelectMany(x => x.Errors));
}

2
또한 반환 할 수 있으며 BadRequest(ModelState)JSON으로 직렬화됩니다.
Fred

6

가장 쉬운 방법 BadRequest은 ModelState 자체 로 a 를 반환하는 것입니다.

예를 들어 PUT:

[HttpPut]
public async Task<IHttpActionResult> UpdateAsync(Update update)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    // perform the update

    return StatusCode(HttpStatusCode.NoContent);
}

Update클래스 에서 휴대 전화와 같은 데이터 주석을 사용하는 경우 :

public class Update {
    [StringLength(22, MinimumLength = 8)]
    [RegularExpression(@"^\d{8}$|^00\d{6,20}$|^\+\d{6,20}$")]
    public string MobileNumber { get; set; }
}

잘못된 요청에 따라 다음을 반환합니다.

{
  "Message": "The request is invalid.",
  "ModelState": {
    "update.MobileNumber": [
      "The field MobileNumber must match the regular expression '^\\d{8}$|^00\\d{6,20}$|^\\+\\d{6,20}$'.",
      "The field MobileNumber must be a string with a minimum length of 8 and a maximum length of 22."
    ]
  }
}

1
BadRequest는 WebAPI 전용이며이 질문은 MVC에 관한 것입니다.
rgripper

5

@ JK 그것은 많은 도움이되었지만 왜 그렇지 않습니까?

 public class ErrorDetail {

        public string fieldName = "";
        public string[] messageList = null;
 }

        if (!modelState.IsValid)
        {
            var errorListAux = (from m in modelState 
                     where m.Value.Errors.Count() > 0 
                     select
                        new ErrorDetail
                        { 
                                fieldName = m.Key, 
                                errorList = (from msg in m.Value.Errors 
                                             select msg.ErrorMessage).ToArray() 
                        })
                     .AsEnumerable()
                     .ToDictionary(v => v.fieldName, v => v);
            return errorListAux;
        }

3

System.Web.Http.Results.OkNegotiatedContentResult를 살펴보십시오.

던지는 모든 것을 JSON으로 변환합니다.

그래서 나는 이것을했다

var errorList = ModelState.ToDictionary(kvp => kvp.Key.Replace("model.", ""), kvp => kvp.Value.Errors[0].ErrorMessage);

return Ok(errorList);

결과는 다음과 같습니다.

{
  "Email":"The Email field is not a valid e-mail address."
}

각 필드에 대해 둘 이상의 오류가있을 때 발생하는 상황을 아직 확인하지 않았지만 요점은 OkNegoriatedContentResult가 훌륭하다는 것입니다!

@SLaks에서 linq / lambda 아이디어를 얻었습니다.


3

기본 제공 기능을 사용하여이를 달성하는 간단한 방법

[HttpPost]
public IActionResult Post([FromBody]CreateDoctorInput createDoctorInput) {
    if (!ModelState.IsValid) {
        return BadRequest(ModelState);
    }

    //do something
}

JSON 결과는


2

ToDictionary는 System.Web.Extensions dll ( http://msdn.microsoft.com/en-us/library/system.linq.enumerable.todictionary.aspx)에 패키지 된 System.Linq에있는 열거 가능한 확장명 입니다. 다음은 완전한 수업의 모습입니다.

using System.Collections;
using System.Web.Mvc;
using System.Linq;

namespace MyNamespace
{
    public static class ModelStateExtensions
    {
        public static IEnumerable Errors(this ModelStateDictionary modelState)
        {
            if (!modelState.IsValid)
            {
                return modelState.ToDictionary(kvp => kvp.Key,
                    kvp => kvp.Value.Errors.Select(e => e.ErrorMessage).ToArray()).Where(m => m.Value.Count() > 0);
            }
            return null;
        }

    }

}

2

원래 ModelState객체를 클라이언트에 반환 한 다음 jQuery를 사용하여 값을 읽으십시오. 나에게 훨씬 간단 해 보이고 공통 데이터 구조 (.net 's ModelState)를 사용합니다.

ModelStateas Json 을 반환하려면 간단히 Json 클래스 생성자에 전달하십시오 (ANY 객체와 함께 작동)

씨#:

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

1

IEnumerable을 반환하는 대신 반환 유형을 사용하는 변형

public static class ModelStateHelper
{
    public static IEnumerable<KeyValuePair<string, string[]>> Errors(this ModelStateDictionary modelState)
    {
        if (!modelState.IsValid)
        {
            return modelState
                .ToDictionary(kvp => kvp.Key, kvp => kvp.Value.Errors.Select(e => e.ErrorMessage).ToArray())
                .Where(m => m.Value.Any());
        }

        return null;
    }
}

0

구분 기호 ""를 사용하여 문자열을 반환하는 확장 프로그램을 만들었습니다.

   public static string GetFullErrorMessage(this ModelStateDictionary modelState) {
        var messages = new List<string>();

        foreach (var entry in modelState) {
            foreach (var error in entry.Value.Errors)
                messages.Add(error.ErrorMessage);
        }

        return String.Join(" ", messages);
    }

-1
  List<ErrorList> Errors = new List<ErrorList>(); 


        //test errors.
        var modelStateErrors = this.ModelState.Keys.SelectMany(key => this.ModelState[key].Errors);

        foreach (var x in modelStateErrors)
        {
            var errorInfo = new ErrorList()
            {
                ErrorMessage = x.ErrorMessage
            };
            Errors.Add(errorInfo);

        }

jsonresult를 사용하면

return Json(Errors);

또는 단순히 modelStateErrors를 반환 할 수 있습니다. 시도하지 않았습니다. 내가 한 것은 오류 컬렉션을 ViewModel에 할당 한 다음 반복하는 것입니다.이 경우 json을 통해 오류를 반환 할 수 있습니다. 클래스 / 모델이 있는데 소스 / 키를 얻고 싶었지만 여전히 알아 내려고 노력하고 있습니다.

    public class ErrorList
{
    public string ErrorMessage;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.