Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where can you find model binding errors in ASP.NET Core MVC?

When performing model binding to objects, it seems that the framework will return null if there are type mismatches for any of the object's properties. For instance, consider this simple example:

public class Client
{
    public string Name { get; set; }
    public int Age { get; set; }
    public DateTime RegistrationDate { get; set; }
}

public class ClientController : Controller
{
    [HttpPatch]
    public IActionResult Patch([FromBody]Client client)
    {
        return Ok("Success!");
    }
}

If I submit a value of "asdf" for the Age property in an HTTP request, the entire client parameter will be null in the Patch method, regardless of what's been submitted for the other properties. Same thing for the RegistrationDate property. So when your FromBody argument is null in your controller action, how can you know what errors caused model binding to fail (in this case, which submitted property had the wrong type)?

like image 282
Nicolas Trahan Avatar asked Mar 12 '18 21:03

Nicolas Trahan


2 Answers

As you stated, ASP.NET MVC core has changed the way MVC API handles model binding by default. You can use the current ModelState to see which items failed and for what reason.

   [HttpPatch]
    [Route("Test")]
    public IActionResult PostFakeObject([FromBody]Test test)
    {
        foreach (var modelState in ViewData.ModelState.Values)
        {
            foreach (var error in modelState.Errors)
            {
              //Error details listed in var error
            }
        }
        return null;
    }
}

The exception stored within the error message will state something like the following:

Exception = {Newtonsoft.Json.JsonReaderException: Could not convert string to integer: pie. Path 'age', line 1, position 28. at Newtonsoft.Json.JsonReader.ReadInt32String(String s) at Newtonsoft.Json.JsonTextReader.FinishReadQuotedNumber(ReadType readType) ...

However, as posted in the comments above, the Microsoft docs explains the following:

If binding fails, MVC doesn't throw an error. Every action which accepts user input should check the ModelState.IsValid property.

Note: Each entry in the controller's ModelState property is a ModelStateEntry containing an Errors property. It's rarely necessary to query this collection yourself. Use ModelState.IsValid instead. https://learn.microsoft.com/en-us/aspnet/core/mvc/models/model-binding

like image 165
PaulBinder Avatar answered Oct 20 '22 18:10

PaulBinder


Just a note, you can write the same logic with

var errors = ViewData.ModelState.Values.SelectMany(x => x.Errors );
foreach(var err in errors) { 
    // Error details listed in err (type is Microsoft.AspNetCore.Mvc.ModelBinding.ModelError)
}

and it's more compact and efficient than the nested foreach loops in the previous answer.

like image 2
rjacobsen0 Avatar answered Oct 20 '22 18:10

rjacobsen0