ASP.NET MVC 2 Model encapsulated within ViewModel Validation
- by Program.X
I am trying to get validation to work in ASP.NET MVC 2, but without much success.
I have a complex class containing a large number of fields. (Don't ask - this is oneo f those real-world situations best practices can't touch) This would normally be my Model and is a LINQ-to-SQL generated class.
Because this is generated code, I have created a MetaData class as per http://davidhayden.com/blog/dave/archive/2009/08/10/AspNetMvc20BuddyClassesMetadataType.aspx.
public class ConsultantRegistrationMetadata
{
[DisplayName("Title")]
[Required(ErrorMessage = "Title is required")]
[StringLength(10, ErrorMessage = "Title cannot contain more than 10 characters")]
string Title { get; set; }
[Required(ErrorMessage = "Forename(s) is required")]
[StringLength(128, ErrorMessage = "Forename(s) cannot contain more than 128 characters")]
[DisplayName("Forename(s)")]
string Forenames { get; set; }
// ...
I've attached this to the partial class of my generated class:
[MetadataType(typeof(ConsultantRegistrationMetadata))]
public partial class ConsultantRegistration
{
// ...
Because my form is complex, it has a number of dependencies, such as SelectLists, etc. which I have encapsulated in a ViewModel pattern - and included the ConsultantRegistration model as a property:
public class ConsultantRegistrationFormViewModel
{
public Data.ConsultantRegistration ConsultantRegistration { get; private set; }
public SelectList Titles { get; private set; }
public SelectList Countries { get; private set; }
// ...
So it is essentially ViewModel=Model
My View then has:
<p>
<%: Html.LabelFor(model => model.ConsultantRegistration.Title) %>
<%: Html.DropDownListFor(model => model.ConsultantRegistration.Title, Model.Titles,"(select a Title)") %>
<%: Html.ValidationMessage("Title","*") %>
</p>
<p>
<%: Html.LabelFor(model => model.ConsultantRegistration.Forenames) %>
<%: Html.TextBoxFor(model => model.ConsultantRegistration.Forenames) %>
<%: Html.ValidationMessageFor(model=>model.ConsultantRegistration.Forenames) %>
</p>
The problem is, the validation attributes on the metadata class are having no effect. I tried doing it via an Interface, but also no effect. I'm beginning to think that the reason is because I am encapsulating my model within a ViewModel.
My Controller (Create Action) is as follows:
[HttpPost]
public ActionResult Create(Data.ConsultantRegistration consultantRegistration)
{
if (ModelState.IsValid) // this is always true - which is wrong!!
{
try
{
consultantRegistration = ConsultantRegistrationRepository.SaveConsultantRegistration(consultantRegistration);
return RedirectToAction("Edit", new { id = consultantRegistration.ID, sectionIndex = 2 });
}
catch (Exception ex)
{
ModelState.AddModelError("CreateException",ex);
}
}
return View(new ConsultantRegistrationFormViewModel(consultantRegistration));
}
As outlined in the comment, the ModelState.IsValid property always returns true, despite fields with the Validaiton annotations not being valid. (Forenames being a key example).
Am I missing something obvious - considering I am an MVC newbie? I'm after the mechanism demoed by Jon Galloway at http://www.asp.net/learn/mvc-videos/video-10082.aspx.
(Am aware t is similar to http://stackoverflow.com/questions/1260562/asp-net-mvc-model-viewmodel-validation but that post seems to talk about xVal. I have no idea what that is and suspect it is for MVC 1)