I get InvalidOperationException when I try to use Metadatatype with a viewmodel

5k views Asked by At

I have a model with certain properties. I use a separated class with the MetadataType to define requirements for properties. I also try to use the same metadata class with a viewmodel defining just a subset of properties. This is a simple example code of the situation for clarification:

[MetadataType(typeof(Metadata))]
class ModelA
{

    public class Metadata
    {
         [Required]
         public object Property1 { get; set; }

         [Required]
         public object Property2 { get; set; }

    }

    public int Property1 { get; set; }
    public int Property2 { get; set; }
}

[MetadataType(typeof(ModelA.Metadata))]
class ViewModelA
{
    public int Property1 { get; set; }
}

The problem is when the razor engine tries to process the view, it throws the an InvalidOperationException with the following error message:

The associated metadata type for type 'ViewModelA' contains the following unknown properties or fields: Property2. Please make sure that the names of these members match the names of the properties on the main type.

In my understanding the problem here is that the metadata contains properties which the the view model does not. However, this way I don't really understand the advantages of having a metadata class. So my questions are

1) Is there a way to prevent of throwing this exception?

2) If not, what it the best pattern to this situation? (like using a model, a viewmodel, which contains the subset of the properties of the model, defining data annotations by keeping the DRY approach).

1

There are 1 answers

4
Erik Funkenbusch On

MetadataTypeAttribute's are typically used in cases where you want to apply Metadata to auto-generated objects. If you were to apply the metadata to the objects themselves, they would be overwritten when the objects were regenerated.

This is typically done via partial classes. For instance see below. In this case, you create an empty partial class that is the same name as the auto-generated class, it's of course named the same, but you add the MetadataType attribute to it, and you include the nested Metadata class within it.

You do not typically use this with other classes, as other classes would have to have identical (or supersets) of properties.

// Do no edit this class as it is auto generated
public partial class ModelA
{
    public int Property1 { get; set; }
    public int Property2 { get; set; }
}

// This class can be edited
[MetadataType(typeof(ModelA.Metadata))]
public partial class ModelA
{
    public class Metadata
    {
         [Required]
         public object Property1 { get; set; }

         [Required]
         public object Property2 { get; set; }

    }
}

So, to answer your questions:

1) No, you can't prevent the exception, because Metadata has to describe all the properties of it's parent class, and if those properties don't exist, it throws.

2) You would have to create alternate metadata classes. Since this is just as much work as creating a stand-alone view-model, there is no real benefit to using buddy classes for view models that are subsets.

A lot of people get caught up in the DRY concept. The problem is that every software implementation has competing requirements. DRY is often at odds with Single Responsibility Principle.

MetadataTypeAttribute is really more of a hack anyways to deal with the way that the designers generate code. If you're using Code First, then I would strongly discourage using MetadataTypeAttribute.