Pete
Pete

Reputation: 58462

Adding Data Annotations to Inherited Class

Say I have the following class:

public class ContactUsFormModel : AddressModel
{
    [DisplayName("Title")]
    [StringLength(5)]
    public string Title { get; set; }
    [DisplayName("First name (required)")]

    [Required(ErrorMessage = "Please enter your first name")]
    [StringLength(50, ErrorMessage = "Please limit your first name to {1} characters.")]
    public string FirstName { get; set; }

    // etc...
}

Am I able to add a required attribute to a property from the AddressModel class in the ContactUsFormModel class?

Upvotes: 17

Views: 12724

Answers (2)

Pete
Pete

Reputation: 58462

Ok I have found a workaround to this by adding a new property to the class:

public bool AddressIsRequired { get; set; }

I could set this when building my model for different forms and then instead of using the normal required attribute, I made my own custom validator:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
public sealed class AddressRequiredAttribute : RequiredAttribute, IClientValidatable
{
    public AddressRequiredAttribute()
        : base()
    {
    }

    protected override ValidationResult IsValid(object value, ValidationContext context)
    {
        Type addresType = typeof(AddressModel);
        if (context.ObjectType == addresType || context.ObjectType.BaseType == addresType)
        {
            AddressModel baseModel = (AddressModel)context.ObjectInstance;
            if (baseModel != null && baseModel.AddressIsRequired)
            {
                return base.IsValid(value, context);
            }
        }

        return ValidationResult.Success;
    }
}

And then in my AddressModel I could mark my properties as such:

[AddressRequired(ErrorMessage = "Please enter your Postcode")]
public string Postcode { get; set; }

I am going to leave this open if anyone is able to find a better way of doing this (ie able to just change the data-annotation without having to make a separate attribute). This way of doing things also means that if you extend the labelfor helper and use the metadata to check the IsRequired flag, the properties marked with this attribute will always be marked as required (I think this could be because it inherits from the required attribute)

Upvotes: 1

Sameer
Sameer

Reputation: 2171

Try to Use MetadatatypeAttribute. Create seprate class for metadata where you directly add attributes to your properties.

[MetadataType(typeof(MyModelMetadata ))]
public class ContactUsFormModel : AddressModel
{
    [DisplayName("Title")]
    [StringLength(5)]
    public string Title { get; set; }
    [DisplayName("First name (required)")]

    [Required(ErrorMessage = "Please enter your first name")]
    [StringLength(50, ErrorMessage = "Please limit your first name to {1} characters.")]
    public string FirstName { get; set; }

    // etc...
}

internal class MyModelMetadata {
    [Required]
    public string SomeProperyOfModel { get; set; }
}

[Edit] Above method is not useful for you, as you said it will not add attributes to base class.

So make the properties in AddressModel virtual and override them in ContactUsFormModel and this way you can add attribute.

Upvotes: 7

Related Questions