MVC Data Annotations and Custom Attributes

So you’ve found out that MVC supports Editor Templates. About 10 min. later you think to yourself hey how can I leverage this to automatically set my textbox width or maxlength and so on. This is a simple example using just a couple classes.

Create Abstract Class Inherit Attribute:

public abstract class MetadataAttribute : Attribute
{
    public abstract void Process(ModelMetadata metaData);
}  

This simply creates a void to process any attributes we set to inherit our class MetadataAttribute. The next piece of code will make sense of this.

Custom Attribute Class:

public class OptionalAttributes : MetadataAttribute
{
    public string style { get; set; }   
    public override void Process(ModelMetadata metaData)
    {
       metaData.AdditionalValues.Add("style", this.style);
    }
}

All we are doing here is creating a public property to store our Attribute value. In this case a simple style (you would probably do something much more relevant to your project this is just for demonstration purposes) Attribute is created. We then must implement our Process as this is inheriting MetadataAttribute.

Adding Attribute to View Model

[OptionalAttributes(style = "width: 150px")]
public string Email { get; set; }

Here we reference our OptionalAttributes Class and expose our style, nothing exciting here.

Wiring it All Up:

public class CustomModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
    protected override ModelMetadata CreateMetadata(
        IEnumerable<Attribute> attributes,
        Type containerType,
        Func<object> modelAccessor,
        Type modelType,
        string propertyName)
    {
        var metaData = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
        attributes.OfType<MetadataAttribute>().ToList().ForEach(x => x.Process(metaData));
        return metaData;
    }
}

This is the magic that makes it all work. Here we create our Metadata Provider inheriting from DataAnnotationsModelMetadataProvider. So basically any Attribute that is of type MetadataAttribute will be processed hence our first abstract class we created.

Adding our Provider to Global.asax:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);

    ModelMetadataProviders.Current = new CustomModelMetadataProvider();
}

Pretty straight forward right. Since we inherit DataAnnotationsModelMetadataProvider we can simply set the ModelMetadataProviders.Current to our CustomModelMetadataProvider;

Making it Happen in Our View:

@model String

    @if (!ViewData.ModelMetadata.AdditionalValues.ContainsKey("style"))
    {         
        @Html.TextBoxFor(model => model)
    }
    else
    {
        var width = ViewData.ModelMetadata.AdditionalValues["style"];   
        @Html.TextBoxFor(model => model, new { style = width })
    }  

O.K so a couple things here. First off what you see is an EDITOR TEMPLATE partial view (you could use the above syntax in your view as well however your model syntax would be more like model => model.Email where Email is the name of your property in your model). Not the strongly typed view itself. Please note that. If you notice the model is of type String.  You can make templates for DateTime or whatever you like. In this case we are describing a simple string. So what is happening here. Well with a simple if else we check to see if the Metadata Key is null. If it has a value we get the value for that key in this case the key is called “style” and then apply it to the style Attribute for our textbox. Now any property in our view model that has a valid value for our Optional Attribute style will be used. No more styling adding css whatever to our view it will all automatically wire up. Can’t stress enough this is NOT a real world implementation but rather just giving you the idea. For instance you should incorporate checking for nulls and correct types but you already know that.

If you really want to be slick create an HtmlHelper to further extend this and do away with the if else statement and handle it all in your HtmlHelper.

No code source on this one. Straight forward just copy from the above, be sure to include your usings or imports of namespaces and you’ll be good.

Advertisements

About Origin1 Technologies

Developer: Asp.Net, MVC, JQuery, MS SQL, VB, C#, Java, Eclipse, Android, Apple, FileMaker Pro and others.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: