ModelState does not check nested models after editing in the controller

I have nested ViewModels, like these two:

public class FirstViewModel { public SecondViewModel SecondViewModel { get; set; } } public class SecondViewModel { [Range(1, 12)] public int month { get; set; } } 

If I put month = 13; and then called ModelState.IsValid (in the controller), the check is always true .

Edit:

This is the controller:

 public ActionResult Create() { return PartialView(new FirstViewModel); } public HttpStatusCodeResult Create (FirstViewModel viewModel){ viewModel.SecondViewModel = new SecondViewModel(); viewModel.SecondViewModel.month = 13; if (ModelState.IsValid) { return new HttpStatusCodeResult(200); } else { return new HttpStatusCodeResult(304); } } 

I am doing an abstraction of the problem, these are not real variables.

+5
source share
3 answers

Your question says that you are "calling ModelState.Validate" in your controller. There is no such method, so I assume you mean if (ModelState.IsValid) .

The first step in the process of model binding is that the parameters of your method are initialized, in your case, a new instance of FirstViewModel . Then the model values ​​are set based on form data, route values, query string values, etc., And any validation errors associated with the properties of your model are added to ModelState .

Subsequently, changing the property value in your model does not affect ModelState , so if the initial value of month valid, then ModelState.IsValid will return true regardless of the setting viewModel.SecondViewModel.month = 13;

If you want to re-test your model, you need to use TryUpdateModel , which returns a bool indicating whether the update was successful

 public HttpStatusCodeResult Create (FirstViewModel viewModel) { viewModel.SecondViewModel = new SecondViewModel(); viewModel.SecondViewModel.month = 13; if (TryUpdateModel(viewModel) { return new HttpStatusCodeResult(200); } else { return new HttpStatusCodeResult(304); } } 
+3
source

Since the SecondViewModel property of the FirstViewModel class is null, it will not be checked. Try adding the required attribute to the attribute:

 public class FirstViewModel { [Required] public SecondViewModel SecondViewModel { get; set; } } public class SecondViewModel { [Range(1, 12)] public int month { get; set; } } 

EDIT

Based on your update, I agree with @StephenMuecke. You cannot instantiate the class yourself and expect the system to check it for you. TryUpdateModel is what you are looking for in this case, or you must let the environment instantiate the class for you. You will need to go through SecondViewModel.month = 13 somewhere in your request to see this in action.

0
source

You can check your model at any time using this

 Validator.TryValidateObject(). 

or for just one property, see this

 Validator.TryValidateProperty() 

Say you have an Address class

 public class Address { [Required] public string Address2 { get; set; } [Required] public string ZipCode{ get; set; } } 

This snippet can be used to validate your object. All errors will be in varibale results.

 var addresse = new Address() { Street = null, ZipCode = null}; var context = new ValidationContext(addresse, null, null); var results = new List<ValidationResult>(); bool isValid = Validator.TryValidateObject(addresse, context, results, true); 
-1
source

All Articles