Home » ASP » ASP.MVC » Why it is wrong to use the Asp.Net MVC MetaDataType Attribute

Why it is wrong to use the Asp.Net MVC MetaDataType Attribute

First of all, let’s talk about MetaDataType attribute and why it exists. This one is from the System.ComponentModel.DataAnnotations.MetadataTypeAttribute namespace. It roles is to add attribute to a class without having to modify this one. You can add this attribute that takes a single parameter to a class that will have all the attribute.

Some rules restraint the use of MetaDataType. It cannot be applied to a property and can be only be applied to a single class for each class type. This attribute cannot be inherited, so you cannot customize it. On the other side, this attribute can be applied to partial class which is the main purpose of this attribute. This attribute will be respected by ASP.NET MVC but will not be read by Entity Framework. This is something interesting if you want to add additional validation or display attribute that does not affect the database. However, it is a good wake up call for any body who use this strategy for validation attributes to know why it should be validated only during the input of the value and not during the save.

Second, from the description we can come to the conclusion that it was implemented for the scenario of Entity Framework with the Database First Approach. The model classes are automatically generated from the EDMX file and even if they are in C# and that you can edit them, you should not. The reason is that if you change your database that you will have to generate the model again which will override your changes. This is why, Entity Framework creates those generated classes as partial class. This allow you to create your own class with the same name and define additional properties, fields and methods. But, what about existing properties that you would want to add attributes? This is where MetaDataType come into play.

//Class from Entity Framework Database First
public partial class YourModelClass
{
    public string YourProperty{get;set;}
}

//Your Partial Class
[MetadataType(typeof(YourModelClassMetaData))]
public partial class YourModelClass
{
}

//The class that add your attributes
public class YourModelClassMetaData
{
    [Required]
    public object YourProperty{get;set;};
}

To illustrate the use of MetaDataType, let’s see an example with Entity Framework. As you can see, the first class of the code snippet is the generated class. This one as all your properties that represent every columns of your table. This class should not be edited by your since the file can be overridden by an automatic tool. This is why the second class come into play. It uses the partial keyword to give your a leverage. You can add new stuffs without touching the generated file. The only constraint is to have the partial keyword and the same class name. This way, .Net can match the classes and merge them into a single class. In this example, we add the MetaDataType attribute that give the capability to a class to delegate the attribute association. This is what we want: to add attribute to existing properties. Having only partial class is not enough because you can add but not attribute because these one must be set over an existing property.

The last class in the code snippet is the one referenced by the MetadataType attribute of the second. It tells .Net Framework to go into this third class, to do reflection to get a property-property association and to move the attribute from the referenced class into the class that the MetadataType attribute has been set. This is why the property type does not matter. Only the name.

In another scenario, where you do not want to add attributes to class that come from Entity Framework, you could have directly into your model class the MetadataType attribute and uncluttered your model from any attribute by having them all in another class.

At the end, what is wrong with MetadataType? It does not seem to hurt anything? Well, this is where I have something that bother me. How come the model class are directly used in the view? This mean that you are using ViewBag, ViewData or something else to pass additional information to the view. This mean that your design is less testable since it relies on a static object mechanism. It is also not required and someone could omit it without breaking anything. It also means that you are splitting your model class into 3 files. One generated, one of yours and one with attributes. This generate a lot of noises just to by-pass a view model approach or to not use Entity Framework Code First (that can be used even if you are working with the database first).

I believe this approach is viable for small application that you know that will not be over 15 entities with not a lot of business logic. It is a tool in the middle of a lot of others. Nevertheless, this is far from being an approach that should be opted to be “the one” that must be used absolutely. This approach end often by having UIHint, mixed with Required, mixed with Display attribute. Some are back-end, some are front-ends, everything is mixed up in a huge class that seem not that huge because it is divided in three.

If you like my article, think to buy my annual book, professionally edited by a proofreader. directly from me or on Amazon. I also wrote a TypeScript book called Holistic TypeScript

7 Responses so far.

  1. Can says:

    It is very clear to understand. You saved my time with this article. Thanks a lot.

  2. Utku says:

    I accept all your arguments, but what do you propose to use as a replacement?

    • Use Code First instead of EDMX. EDMX will not be supported with the new Entity Framework 7 anyways. Also, use View Model object and Model object. This way, both classes can have attribute that belong to each of them.

      • joe says:

        I hate using Code First, me thinks it’s the lazy way out. I am old school, for an enterprise system i usually design the data model first, get the Entities analyzed and normalized, ER diagrams drawn, etc etc.. and then worry about the code.

        I don’t understand why the sudden push for Code first, it’s similar to when there was the sudden push for asp.net web forms and magic from Classic asp, but now we’ve gone back to Webpages, which is more similar to asp Classic.

        • The data does not drive most business — the business drive it. That mean that you should worry first about doing the task and later about how to persist this one. I am not sure I am following you with “the lazy way out”. For me, what we see in the industry make sense. You design how your code will fulfill your goal, the relationship between classes, how everything will be layered or/and serviced and at some point you define where that information will be stored. It can be in a cache system, in a SQL database, in a NoSql database, in a service, etc. Starting the other way around lead to have design focused on the database which end up having solution that are less flexible in term of changing the persistence or scale for the web.

          I also do not understand your “back to webpage”. The trend is to have webservice that get the information and everything for the UI is built with JavaScript (with framework like Angular). This is really not Asp Classic where you had your logic inside the Aspx (view).

  3. Eregrith says:

    What does adding a Metadata class has to do with anything ViewModel’s side?
    I am currently in the process of adding metadata to my entities to enforce custom business validation rules, based on custom attributes. This does not prevent me from having a specific view model with its attributes (often using the same logic for the same rules), but we have to register that not everything is validated as a viewmodel before landing in the persistence. Any piece of code could create an instance of YourModelClass and easily bypass the ViewModel validation if only it is decorated with attributes.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.