This doesn't make any sense to me.
Look at this ViewModel:
public class SelectService
{
[Required]
public int? SelectedServiceId { get; set; }
}
Look at this Action:
[HttpPost]
public virtual ActionResult SelectService()
{
TryUpdateModel(WizardContainer.SelectService, "SelectService");
TryValidateModel(WizardContainer.SelectService, "SelectService"); // if I remove this, ModelState.IsValid will always be true
if (ModelState.IsValid)
{
return RedirectToAction("OtherAction");
}
else
{
return View(WizardContainer);
}
}
Now read this exceprt from Apress ASP.NET MVC 2 Framework by S. Sanderson:
Whenever you use model binding to populate a model object—either by receiving it as an action method parameter, or by calling UpdateModel() or TryUpdateModel() manually—then DefaultModelBinder will automatically run the validators associated with all model objects that it has updated (i.e., ones where it has set a value on at least one property). If you update a model object in any other way, its validators will not be run unless you explicitly tell the framework to run them.
So, why then is validation never occuring when I call TryUpdateModel()? To get validation to occur, I have to explicitly validate using TryValidateModel().
UPDATE
Here is a very similar action in the same controller that works as expected:
[HttpPost]
public virtual ActionResult Index(string nextButton)
{
TryUpdateModel(WizardContainer.Index);
if (nextButton != null && ModelState.IsValid)
{
return RedirectToAction("OtherAction");
}
else
{
return View(WizardContainer.Index);
}
}
And here is it's ViewModel:
public class Index
{
[Required]
public DateTime? SelectedServiceTime { get; set; }
}
Update 2
I changed some things and now it behaves as expected, but I still don't understand why.
Look at the edited action:
[HttpPost]
public virtual ActionResult SelectService()
{
TryUpdateModel(WizardContainer.SelectService);
//TryValidateModel(WizardContainer.SelectService, "SelectService"); // not needed anymore
if (ModelState.IsValid)
{
return RedirectToAction("OtherMethod");
}
else
{
return View(WizardContainer.SelectService);
}
}
The difference now being only that the object that I am passing to TryUpdateModel() is the object I am passing to the view instead of being a property of the object that I pass to the view. What the deal yo?