Custom ASP.Net MVC 2 ModelMetadataProvider for using custom view model attributes

There are a number of ways of implementing a pattern for using custom view model attributes, the following is similar to something my colleague Paul Haley and I developed at work which works pretty well.

The classes I’m going to create are really simple:

1. Abstract base attribute

2. Custom ModelMetadata provider which will derive from the DataAnnotationsModelMetadataProvider

Base Attribute

MetadataAttribute
  1. using System;
  2. using System.Web.Mvc;
  3. namespace Mvc2Templates.Attributes
  4. {
  5.     /// <summary>
  6.     /// Base class for custom MetadataAttributes.
  7.     /// </summary>
  8.     public abstract class MetadataAttribute : Attribute
  9.     {
  10.         /// <summary>
  11.         /// Method for processing custom attribute data.
  12.         /// </summary>
  13.         /// <param name="modelMetaData">A ModelMetaData instance.</param>
  14.         public abstract void Process(ModelMetadata modelMetaData);
  15.     }
  16. }

As you can see, the class simple has one method – Process.

Process accepts the ModelMetaData which will allow any derived custom attributes to set properties on the model meta data and add items to its AdditionalValues collection.

Custom Model Metadata Provider

For a quick explanation of the Model Metadata and how it fits in to the MVC 2 framework, it is basically a set of properties that are usually set via attributes placed above properties on a view model, for example the ReadOnly and HiddenInput attributes.

When EditorForModel, DisplayForModel or any of the other EditorFor/DisplayFor methods are called, the ModelMetadata information is used to determine how to display the properties.

All of the information available within the model metadata is also available through ViewData.ModelMetadata.

The following class derives from the DataAnnotationsModelMetadataProvider built into the mvc 2 framework.

I’ve overridden the CreateMetadata method in order to process any custom attributes that may have been placed above a property in a view model.

CustomModelMetadataProvider
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Web.Mvc;
  5. using Mvc2Templates.Attributes;
  6. namespace Mvc2Templates.Providers
  7. {
  8.     public class CustomModelMetadataProvider : DataAnnotationsModelMetadataProvider
  9.     {
  10.         protected override ModelMetadata CreateMetadata(
  11.             IEnumerable<Attribute> attributes,
  12.             Type containerType,
  13.             Func<object> modelAccessor,
  14.             Type modelType,
  15.             string propertyName)
  16.         {
  17.             var modelMetadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
  18.             attributes.OfType<MetadataAttribute>().ToList().ForEach(x => x.Process(modelMetadata));
  19.             return modelMetadata;
  20.         }
  21.     }
  22. }

 

As you can see, once the model metadata is created through the base method, a check for any attributes deriving from our new abstract base attribute MetadataAttribute is made, the Process method is then called on any existing custom attributes with the model meta data for the property passed in.

Hooking it up

The last thing you need to do to hook it up is set the new CustomModelMetadataProvider as the current ModelMetadataProvider, this is done within the Global.asax Application_Start method.

Global.asax
  1. protected void Application_Start()
  2.         {
  3.             AreaRegistration.RegisterAllAreas();
  4.             RegisterRoutes(RouteTable.Routes);
  5.             ModelMetadataProviders.Current = new CustomModelMetadataProvider();
  6.         }

In my next post, I’m going to demonstrate a cool custom attribute that turns a textbox into an ajax driven AutoComplete text box.

Hope this is useful.

Kind Regards,

Sean McAlinden.

5 Comments

Comments have been disabled for this content.