Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combine data annotation attributes

I have a collection of several attributes that should all be used always together for UI and Validation. For example for a currency field, I have to add a UI Hint, Validation Logic, and Display Formatting. As a result, my class looks very crowded.

public class Model
{
    [UIHint("Currency")]
    [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:C}")]
    [CustomRegularExpression(Currency.ValidationPattern, OnlyOnClientSide = true)]
    [SetMetaDataForCustomModelBinder("Currency")]
    public double? Cost { get; set; }

    [UIHint("Currency")]
    [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:C}")]
    [CustomRegularExpression(Currency.ValidationPattern, OnlyOnClientSide = true)]
    [SetMetaDataForCustomModelBinder("Currency")]
    public double? Profit { get; set; }
}

Is there any way to create a [Currency] attribute that combines the functionality of all these attributes to be one simple attribute? My goal would be to create the following:

public class Model
{
    [Currency] public double? Cost { get; set; }
    [Currency] public double? Profit { get; set; }
}

EDIT: To clarify, I have tried creating a custom attribute, but there are no interfaces exposed that would allow me to implement the functionality of those different attributes. I can subclass ValidationAttribute, but then I cannot also subclass UIHintAttribute. Any other potential solutions I'm missing?

like image 497
Matt Murrell Avatar asked Feb 12 '13 16:02

Matt Murrell


1 Answers

According to the post and a reference from the post to Phil Haack's article you can create your custom AssociatedMetadataProvider that adds attributes you need. You will have something like this:

public class MyCustomMetadataProvider : DataAnnotationsModelMetadataProvider
{
    protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
    {
        var attributeList = attributes.ToList();
        if (attributeList.OfType<CurrencyAttribute>().Any())
        {
            attributeList.Add(new UIHintAttribute("Currency"));
            attributeList.Add(new DisplayFormatAttribute
            {
                ApplyFormatInEditMode = true, 
                DataFormatString = "{0:C}"
            });
        }

        return base.CreateMetadata(attributeList, containerType, modelAccessor, modelType, propertyName);
    }
}

And in application start event:

ModelMetadataProviders.Current = new MyCustomMetadataProvider();
like image 90
nexuzzz Avatar answered Dec 02 '22 04:12

nexuzzz