Reputation: 18387
I have the following ViewModel:
public class MyViewModel:IValidatableObject
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime? Birthday { get; set; }
public int Status { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (string.IsNullOrWhiteSpace(Name))
yield return new ValidationResult("Please fill the name", new string[] { "Name" });
if (Birthday.HasValue == false)
yield return new ValidationResult("Please fill the birthday", new string[] { "Birthday" });
if(Status <= 0)
yield return new ValidationResult("Please fill the status", new string[] { "Status" });
}
}
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Id,Name,Birthday,Status")] MyViewModel myViewModel)
{
if (ModelState.IsValid)
{
db.MyViewModels.Add(myViewModel);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(myViewModel);
}
I would like to display all the validation messages at the same time, however it shows first status and then the other two properties.
Upvotes: 0
Views: 687
Reputation: 11773
This is due to the order in which validation happens. First the ModelBinder does it's job, and if that passes, since you've created a self validating viewmodel by implementing IValidatableObject
, the Validate
method is called. In the first screenshot the modelbinding process is failing so Validate is never called. In the second screenshot, modelbinding succeeds, but Validate()
fails.
You can solve this by using DataAnnotations instead of implementing IValidatableObject
like so:
public class MyViewModel:IValidatableObject
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public DateTime Birthday { get; set; }
[Required, Range(0, Int32.MaxValue)]
public int Status { get; set; }
}
Upvotes: 1