Sunday, March 24, 2013

Applying Attributes to Tool-Generated Classes

Something I ran into a while back, using Linq to SQL (prior to EF Code First), was getting some meta-data onto the models generated by Visual Studio. If you add an Attribute to the generated code, there is a pretty good chance you are going to lose your hard work whenever you re-run the tool. I found this question, on Stack Overflow, asking about this exact problem and was able to help somebody out. I figured this would be a great place to share the code, as well, so I don't have to search for it later.

Most of the tool-generated code that we run into is going to be made out of a partial class. All we have to do is create a new class with the same name (partial as well, of course) and decorate it with the MetadataTypeAttribute. We supply the attribute with the type of a new class that looks like the class we want to extend with the attributes we want to apply. This probably sounds more complicated than it is. So, some sample code should help.

Let's say that our tool generated a class called "GeneratedByOurTool" and it has a string property "SomeProperty"—original, I know. Now we want to pass that directly to some MVC view (yuck, I know) and want to use the Razor helper methods to generate a label for our property. Well, in its current state, Razor is going to write out "SomeProperty" because it doesn't know that you really wanted a space in there.

namespace ExtendingGeneratedCode
{
    using System.ComponentModel.DataAnnotations;

    // This class is generated by a tool
    public partial class GeneratedBySomeTool
    {
        public string SomeProperty { get; set; }
    }


    // We hand wrote the following two
    [MetadataType (typeof (MyMetadataClass))]
    public partial class GeneratedBySomeTool { }

    public class MyMetadataClass
    {
        [Display (Name = "Some Property")]
        public string SomeProperty { get; set; }
    }
}

So, we create a new partial class (in a new file, otherwise it can be overwritten by the tool!) with the same name as the one generated by the tool. In our case, it is "GeneratedBySomeTool." We then decorate our new class with the MetadataTypeAttribute and point it to a third class that holds the metadata in which we are interested.

I will normally put the two hand-written classes into the same file to save from having to hunt them down. Also, note, the hand-written version of GeneratedBySomeTool is empty. You can put new properties or methods here, though, if you want to extend the tool-generated version of the class without using inheritance.

MetadataTypeAttribute resides in the System.ComponentModel.DataAnnotations assembly, in the same namespace as the assembly.

No comments:

Post a Comment