views:

978

answers:

2

Inherited properties and MetadataType does not seem to work with client side validation in ASP.NET MVC 2.

The validation of our MetadataTypes work as expected on the server but for some reason it does not generate the appropriate client scripts for it. Client side validation kicks in as expected for properties with the DataAnnotations attributes set on the PersonView so I know that client side validation is active and that it works. Does anyone know if or how it can be fixed?

Here's what we have:

public abstract class PersonView
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
    [Required] public string PhoneNumber { get; set; }
    public string AddressLine1 { get; set; }
    public string AddressLine2 { get; set; }
    public string AddressZipCode { get; set; }
    public string AddressCity { get; set; }
    public string AddressCountry { get; set; }
}

[MetadataType(typeof(CustomerViewMetaData))]
public class CustomerView : PersonView {}

[MetadataType(typeof(GuestViewMetaData))]
public class GuestView : PersonView {}

public class GuestViewMetaData
{
    [Required(ErrorMessage = "The guests firstname is required")] public string FirstName { get; set; }
    [Required(ErrorMessage = "The guests lastname is required")] public string LastName { get; set; }
}

public class CustomerViewMetaData
{
    [Required(ErrorMessage = "The customers firstname is required")] public string FirstName { get; set; }
    [Required(ErrorMessage = "The customers lastname is required")] public string LastName { get; set; }
    [Required(ErrorMessage = "The customers emails is required")] public string Email { get; set; }
}

As you can see, it's nothing fancy or strange in there... Can it be fixed? Is it a bug in ASP.NET MVC 2?

A: 

Are you sure? I've got a ASP.NET MVC 2 site set up as you describe and I have client side validation of both required and regex based attributes that works fine. It doesn't work with my own validators (that derive from ValidationAttribute) at the moment though:

[MetadataType(typeof(AlbumMetadata))]
public partial class Album {}

public class AlbumMetadata {
    [Required(ErrorMessage = "You must supply a caption that is at least 3 characters long.")]
    [MinLength(3, ErrorMessage = "The caption must be at least {0} characters long.")]
    [RegularExpression(@".{3,}")]
    public string Caption { get; set; }
}

(MinLength basically provides a more obvious way to see what's happening in the Regular Expression attribute, which was added for testing)

I then have the following in my view:

<script src="/Scripts/MicrosoftAjax.js" type="text/javascript"></script>
<script src="/Scripts/MicrosoftMvcValidation.js" type="text/javascript"></script>

<%= Html.ValidationSummary("Edit was unsuccessful. Please correct the errors and try again.") %>
<% Html.EnableClientValidation(); %>
<% using (Html.BeginForm()) {%>
<fieldset>
    <legend>Album details</legend>
    <div class="form_row">
        <label for="Caption" class="left_label">Album caption:</label>
        <%= Html.TextBox("Caption", Model.Caption, new { @class = "textbox" })%>
        <%= Html.ValidationMessage("Caption", "*") %>
        <div class="cleaner">&nbsp;</div>
    </div>
    <div class="form_row">
        <label for="IsPublic" class="left_label">Is this album public:</label>
        <%= Html.CheckBox("IsPublic", Model.IsPublic) %>
    </div>
    <div class="form_row">
        <input type="submit" value="Save" />
    </div>
</fieldset>
<% } %>

Which results in the following being output to the client below the form tags (formatted for clarity):

<script type="text/javascript">
//<![CDATA[
if (!window.mvcClientValidationMetadata)
{ window.mvcClientValidationMetadata = []; }
window.mvcClientValidationMetadata.push({
    "Fields":[
      {"FieldName":"Caption",
       "ReplaceValidationMessageContents":false,
       "ValidationMessageId":"Caption_validationMessage",
       "ValidationRules":[
         {"ErrorMessage":"You must supply a caption that is at least 3 characters long.",
          "ValidationParameters":{},
          "ValidationType":"required"},
         {"ErrorMessage":"The field Caption must match the regular expression \u0027.{3,}\u0027.",
          "ValidationParameters":{"pattern":".{3,}"},
          "ValidationType":"regularExpression"}]
      }],
      "FormId":"form0","ReplaceValidationSummary":false});
//]]>
</script>
Zhaph - Ben Duguid
It's hard to tell when I don't have the other part of the Album class but are you really inheriting from a base class in your Album partial? Have a look at my answer.
Kristoffer Ahl
@Kristoffer Ahl - Album is part of my Entity Framework Data Model, so yes, it's definitely inheriting from something: `public partial class Album : global::System.Data.Objects.DataClasses.EntityObject` (from the Designer.cs file attached to the .edmx file), and that contains a decorated Caption property (`[EdmScalarPropertyAttribute(IsNullable=false)]` and `[DataMemberAttribute()]`)
Zhaph - Ben Duguid
+1  A: 

According to a Microsoft official this is a bug in ASP.NET MVC 2. I was given the link below and although the scenario isn't exactly the same, it seems to be the same problem. As far as I can tell it is related to inhertited properties and DataAnnotations model metadata provider. The link says they will try to fix the issue in ASP.NET MVC 3.

Asp.net MVC 2 RC2: the client side validation does not work with overridden properties

Kristoffer Ahl
Glad you found that the problem. Thanks for posting the update!
SkippyFire
@SkippyFire and @Kristoffer, any news on whether this has been fixed in any versions so far?
Drew Noakes