Search code examples
c#entity-frameworkasp.net-web-apimodelstate

ModelState Errors for all Navigation Properties


I am having issues with my WebApi and the ModelState. Whenever I send data to my API it throws ModelState errors on all navigation properties. This is my model:

public class Student
{
    public int StudentID { get; set; }
    public string StudentName { get; set; }
    public int StandardId { get; set; }
    public Standard Standard { get; set; }
}

public class Standard
{
    public int StandardId { get; set; }
    [Required]
    public string StandardName { get; set; }

    public ICollection<Student> Students { get; set; }
}

As you can see I did not assign the virtual keyword which should not be an issue since I don't want lazy loading.

This is my API:

[HttpPut, Route("updateStudent/{id:int}")]
public IHttpActionResult Put(int id, Student student)
{
    // ModelState throws an error here!!
    if (ModelState.IsValid && id == student.StudentId) {
    ...
    }
}

This is how my request looks:

{
   "StudenID": 0,
   "StudentName": "Tom",
   "StandardId": 1
}

When I inspect how the model looks like when it arrives in the api, I can see that all the data is populated and it basically replaces the Standard property with a new Standard instance. However, I don't want it to throw the validation errors of course.

Edit: It throws the error saying that the StandardName property is required. Obviously this is a proprty part of the navigation property. I don't want to checkthe navigation property for errors.


Solution

  • You should create a new model which should contain only those items that will be posted as input and communicate it with your Data Model in the controller action. You can create a ViewModel in your case like:

    public class StudentViewModel
    {
        public int StudentID { get; set; }
        public string StudentName { get; set; }
        public int StandardId { get; set; }
    }
    

    and accordingly change the action method parameter.

    [HttpPut, Route("updateStudent/{id:int}")]
    public IHttpActionResult Put(int id, StudentViewModel student)
    {
    
        if (ModelState.IsValid && id == student.StudentId) {
        ...
        // map with your Student Entity here  as per your needs
        }
    }
    

    For a work around at the moment you could remove those Standard entity properties from ModelState:

    public IHttpActionResult Put(int id, Student student)
    {
         // ignore StandardName property
         ModelState.Remove(nameof(student.Standard.StandardName));
    
         if (ModelState.IsValid && id == student.StudentId) {
        ...
    }