How do you get a list of all ModelState error messages? I found this code to get all the keys: ( Returning a list of keys with ModelState errors)
var errorK
Simple way achieve this by using built-in functionality
[HttpPost]
public IActionResult Post([FromBody]CreateDoctorInput createDoctorInput) {
if (!ModelState.IsValid) {
return BadRequest(ModelState);
}
//do something
}
JSON result will be
I made and extension that returns string with seperator " " (you can use your own):
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);
}
I like to use Hashtable
here, so that I get JSON object with properties as keys and errors as value in form of string array.
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 });
This way you get following response:
{
"success":false,
"errors":{
"Phone":[
"The Phone field is required."
]
}
}
Here is the full implementation with all the pieces put together:
First create an extension method:
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;
}
}
Then call that extension method and return the errors from the controller action (if any) as json:
if (!ModelState.IsValid)
{
return Json(new { Errors = ModelState.Errors() }, JsonRequestBehavior.AllowGet);
}
And then finally, show those errors on the clientside (in jquery.validation style, but can be easily changed to any other style)
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());
}
}
@JK it helped me a lot but why not:
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;
}
The easiest way to do this is to just return a BadRequest
with the ModelState itself:
For example on a PUT
:
[HttpPut]
public async Task<IHttpActionResult> UpdateAsync(Update update)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
// perform the update
return StatusCode(HttpStatusCode.NoContent);
}
If we use data annotations on e.g. a mobile number, like this, in the Update
class:
public class Update {
[StringLength(22, MinimumLength = 8)]
[RegularExpression(@"^\d{8}$|^00\d{6,20}$|^\+\d{6,20}$")]
public string MobileNumber { get; set; }
}
This will return the following on an invalid request:
{
"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."
]
}
}