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.
Handing Resources
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.
ModelMetatdataProviders
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.
DependencyResolver.SetResolver(new UnityDependecyResolver(unityContainer));
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
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.
Summary
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
This article has been editorially reviewed by Suprotim Agarwal.
C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.
We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).
Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.
Click here to Explore the Table of Contents or Download Sample Chapters!
Was this article worth reading? Share it with fellow developers too. Thanks!
Raj Aththanayake is a Microsoft ASP.NET Web Developer specializing in Agile Development practices such Test Driven Development (TDD) and Unit Testing. He is also passionate in technologies such as ASP.NET MVC. He regularly presents at community user groups and conferences. Raj also writes articles in his blog
http://blog.rajsoftware.com. You can follow Raj on twitter @raj_kba