Storing metadata about your model is a great feature that ASP.NET MVC 2 introduced. These metadata are described by the DataAnnotation attributes which is built into .NET Framework. Metadata also enable a great way to specify Validation attributes, so the MVC Validation system can use those DataAnnotation Metadata attributes to provide Validation. In this article, we will discuss the DataAnnotation’s DisplayAttribute and how ModelMetadataProviders operate within ASP.NET MVC framework.
The difference between DisplayNameAttribute and MVC 3 new DisplayAttribute
You may already know that ASP.NET MVC 2 introduced the DisplayNameAttribute which is part of the System.ComponentModel namespace. This attribute allowed us to display the name of the customer as the “Customer Name” instead of the actual property name: “Name”.
ASP.NET MVC 3 now supports DisplayAttribute in System.ComponentModel.DataAnnotation namespace. DisplayAttribute is new in .NET 4.
So what is the real difference between the “DisplayAttribute”, and the “DisplayNameAttribute”? They serve the same purpose, which is displaying a custom string, however the key difference is in the overloads they provide.
“DisplayAttribute” supports more overloads than the “DisplayNameAttribute”.
“DisplayNameAttribute” only supports a string which is the DisplayName.
Even though it doesn’t make sense to do so, what happens if we were to specify both attributes?
In this situation, the new DisplayAttribute takes precedence over the DisplayNameAttribute. Instead of the “Customer name 2” we should see the “Customer name 1” displayed to the user.
In some cases, we need the DisplayAttribute to be resource sensitive. For an example, instead of using non-localized resources, we might want to use the standard .NET resource provider to retrieve the localized resources. Please refer to MSDN documentation for more information on ASP.NET localization.
Below is a simple example on how to configure the resources so they can be displayed based on the localization.
As we did for the above DisplayAttribute, it is not straightforward to make DisplayNameAttribute to be resource sensitive. DisplayNameAttribute does not support a parameter for ResourceType. In that case, we need to subclass the DisplayNameAttribute and provide our own implementation similar to below.
Below is the usage of new sub classed attribute:
Annotating on MVC Model’s Metadata
So far we have discussed the System.ComponentModel.DataAnnotation.DisplayAttribute and how it is different to System.ComponentModel.DisplayNameAttribute.
Each metadata attribute provided by the System.ComponentModel.DataAnnotation has a specific purpose. Please refer to MSDN documentation for more information on each DataAnnotation attribute.
In this section, we will discuss how all DataAnnotation attributes are consumed within ASP.NET MVC 3 framework.
ModelMetadataProviders provide the currently configured ModelMetadataProvider. MVC uses a built-in ModelMetadataProvider which is called DataAnnotationsModelMetadataProvider. MVC ModelMetadataProvider can be extended to create our own ModelMetadataProvider. Below is an example on how we could implement our own custom ModelMetadataProvider (MyModelMetadataProvider) to consume a custom metadata attribute called MyMetaDataAttribute.
The custom ModelMetadataProvider needs to be registered so it can be used within the MVC framework.
We could use static registration to register a custom ModelMetadataProvider.
ModelMetadataProviders.Current = new MyModelMetadataProvider();
In ASP.NET MVC 3, we could also use our favourite IOC container to register a custom ModelMetadataProvider. For example, if the IOC container is the Unity container, we could register our own ModelMetadataProvider as below.
This also assumes that we have already configured the DependecyResolver as shown below.
Once the DependecyResolver is configured, MVC uses the implementation of an IResolver<T> interface, which is SingleServiceResolver<TService> to resolve the custom implementation of a ModelMetadataProvider.
Within the implementation of SingleServiceResolver<TService>, there is a call to “DependencyResolver.Current” to retrieve the static instance of a currently configured DependencyResolver i.e UnityDependencyResolver. As specified in the MVC 3 ModelMetadataProviders.cs class, ModelMetadataProviders uses the resolver to discover the configured ModelMetadataProvider.
If the ModelMetaDataProvider is not resolvable via the configured UnityDependecyResolver, MVC falls back to the static registration point of the ModelMetadataProvider. If the same custom ModelMetadataProvider is configured via both IOC and via the static registration, MVC throws the following exception.
“An instance of ModelMetadataProvider was found in the resolver as well as a custom registered provider in ModelMetadataProviders.Current. Please set only one or the other. “
DataAnnotationsModelMetadataProvider is the class which is ultimately responsible for creating Metadata based on the attributes defined by the System.ComponentModel.DataAnnotation namespace. We have discussed the DisplayAttribute as an example to provide certain metadata conditions such as displaying a custom name.
Whenever the system requests metadata associated for a certain property, MVC uses the currently configured ModelMetadataProvider to request metadata associated for the model’s property.
ModelMetadataProviders.Current.GetMetadataForProperty(modelAccessor, containerType, propertyName);
Since DataAnnotationsModelMetadataProvider does not override the GetMetadataForProperty method, MVC uses the AssociatedMetadataProvider’s GetMetadataForProperty method to discover the model’s metadata by passing the propertyName. In turns, AssociatedMetadataProvider calls CreateMetadata method which is overridden by the DataAnnotationsModelMetadataProvider’s CreateMetadata() to create model’s metadata.
Based on the property’s attribute(s), the above CreateMetadata() method creates a DataAnnotationsModelMetadata object for the associated property.
As we see in the above diagram, DataAnnotationsModelMetadata is derived from the ModelMetadata. This object is returned to the client i.e to an Html helper method and extracts the data associated for the property name. MVC constructs Html based on the returned object and send html to the browser.
An example would be if the Html helper is used to render a label, the metadata DisplayName can be extracted as below.
ASP.NET MVC provides a great support for DataAnnotation attributes which can be used to enable rich metadata behaviour within MVC models. ASP.NET MVC 3 introduced the support for new DataAnnotation DisplayAttribute. ModelMetadataProvider can be used to create ModelMetadata based on the model’s attributes.
ModelMetadataProvider is extensible and we could easily create our own MetadataProvider to support any custom behaviour. ASP.NET MVC 3 also introduced new registration point for IOC users to support registration of custom ModelMetadataProviders.
The entire source code of this article can be downloaded over here