views:

224

answers:

1

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)

+1  A: 

I've been trying to make this work for some time. Based on the code you've included I think you're doing it right.

I think the problem is with the javascript validators that are supposed to be "emitted" into the page. There are several other questions here on SO relating to this problem and I don't think any of them offer a solution that works across the board. As far as I can tell, MVC2 RC is still broken.

UPDATE:

If it works when you apply the attributes to the emitted code, take a look at this:

http://stackoverflow.com/questions/2547132/when-using-data-annotations-with-mvc-pro-and-cons-of-using-an-interface-vs-a-me

It may be the MetadataType attribute that's not working. Does it work if you try an interface as suggested in the question above?

Also, another question: http://stackoverflow.com/questions/2475906/metadatatype-and-client-validation-in-asp-net-mvc-2

That one is fairly recent and confirms that this is still a bug in MVC2.

Dave Swersky
Ah, great. It works (not JS, but half is as good) if I apply the attributes directly on the LINQ-to-SQL generated code. Obviously not a solution.
Program.X
Updated answer...
Dave Swersky
Thanks Dave. I'll have to wait till Wednesday to have a look as I'm off work for a bit. Noted, though.
Program.X
Program.X