ASP.NET MVC как конвертировать ошибки ModelState в json
Как вы получаете Список всех сообщений об ошибках 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...
12 ответов:
вы можете поставить что-нибудь вы хотите, чтобы внутри
selectстатья:var errorList = (from item in ModelState where item.Value.Errors.Any() select item.Value.Errors[0].ErrorMessage).ToList();EDIT: вы можете извлечь несколько ошибок в отдельные элементы списка, добавив
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 nd EDIT: Вы ищете
Dictionary<string, string[]>:var errorList = ModelState.ToDictionary( kvp => kvp.Key, kvp => kvp.Value.Errors.Select(e => e.ErrorMessage).ToArray() );
вот полная реализация со всеми частями вместе взятыми:
сначала создайте метод расширения:
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.стиль проверки, но может быть легко изменен на любой другой стиль)
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()); } }
мне нравится использовать
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." ] } }
есть много различных способов сделать это, что все работают. Вот теперь я это делаю...
if (ModelState.IsValid) { return Json("Success"); } else { return Json(ModelState.Values.SelectMany(x => x.Errors)); }
@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; }
взгляните на систему.Сеть.Http.Результаты.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 является блестящим!
получил идею linq/lambda от @SLaks
самый простой способ сделать это, чтобы просто вернуть
BadRequestС самим ModelState:например, на
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." ] } }
ToDictionary-это Перечисляемое расширение, найденное в системе.LINQ, которая упакована в системе.Сеть.Расширения dll http://msdn.microsoft.com/en-us/library/system.linq.enumerable.todictionary.aspx. Вот как выглядит полный класс для меня.
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; } } }
почему бы не вернуть оригинал
ModelStateобъект для клиента, а затем использовать jQuery для чтения значений. Для меня это выглядит намного проще, и использует общую структуру данных (.netModelState)вернуть
ModelStateкак Json, просто передайте его конструктору класса Json (работает с любым объектом)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); }
простой способ добиться этого с помощью встроенной функциональности
[HttpPost] public IActionResult Post([FromBody]CreateDoctorInput createDoctorInput) { if (!ModelState.IsValid) { return BadRequest(ModelState); } //do something }
вариация с типом возврата вместо возврата 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; } }
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, а затем цикл it..In в этом случае я могу вернуть свои ошибки через json. У меня есть класс/модель, я хотел получить источник/ключ, но я все еще пытаюсь понять это.
public class ErrorList { public string ErrorMessage; }
Comments