Thursday, April 10, 2014

Auto Generate Meta Data Classes for Data Annotations via MVCScaffolding.MetaDataPlugin

If you are like me, you like to separate the data annotations into separate meta data classes not only for Entity Framework but for my view models and other model classes.

The only pain of this is amount of tedious and repetitive code that has to be done to get it all wired up.  A fellow developer and myself were discussing this pain point and decided to utilized the power of MVC Scaffolding to create a T4 template that will stub out the very basics of the meta data class for a given model.

A day later and here we sit with a working NuGet package that does just this for any project.

http://www.nuget.org/packages/MVCScaffolding.MetaDataPlugin/

Instructions on how to use this package are in the readme.txt that will open upon install of the package.

For Example for the below class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace ScaffoldingExample.Models
{
 
public partial class TestVM
  {
 
      public string FirstName { get; set; }
       public string LastName { get; set; }
       public string Email { get; set; }
       public string Address1 { get; set; }
       public string Address2 { get; set; }
       public string City { get; set; }
       public string State { get; set; }
       public string Zip { get; set; }
  }

}
 


I would run the following command in the Package Management Console
PM> Scaffold MetadataClass TestVM

This will add TestVM.cs to the MetaDataClasses folder under the Models folder. (If these folders do not exist it will create them)

The following is the example file it generated:
//------------------------------------------------------------------------------
//
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// Date generated: 4/10/2014 4:44 PM
//
//------------------------------------------------------------------------------


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;

namespace ScaffoldingExample.Models
{
      [MetadataType(typeof(TestVMMetadata))]
      public partial class TestVM
      {
      }
 
     
     
      public class TestVMMetadata
      {           
            public object FirstName { get; set; }
            public object LastName { get; set; }
            public object Email { get; set; }
            public object Address1 { get; set; }
            public object Address2 { get; set; }
            public object City { get; set; }
            public object State { get; set; }
            public object Zip { get; set; }
      }
}
 


There are a few important things to note
  1. Because this uses T4 Scaffolding you must successfully build the project so that the proper dll is referenced.
  2. If you work on the same project on multiple machines you will need to un-install and re-install the package so that they proper assembly and project paths are used in the T4 Template.  (you could manually modify the full path to the assemblies in the t4 template)
  3. It will only work on models that existing in the Project.Models namespace
Support for Areas (v1.0.6+)

To use this with areas simply specify the option -Area parameter.  If the above class was in the models folder of an area named "TestArea" the following would be the command to run in the Package Management Console:

PM> Scaffold MetadataClass TestVM -Area TestArea

Support for Custom Namespaces and Destination Folders and enhanced EF support (v1.1.0+)

If your project does not follow MVC conventions you can now specify the custom namespace via the Namespace parameter.  If you prefer to specify a custom output directory for the MetaDataClasses you can implement this via the Destination parameter.  The following is an example commmand to run in Package Management Console:

PM> Scaffold MetadataClass TestVM -Area TestArea -Namespace ScaffoldingExample.Models.TestVM -Destination MyMetaDataClasses

The Entity Framework enhancements in this version added filtering of the output to prevent the EntityState, EntityKey, EntityReference, EntityObject types from being output as generic object properties in the MetaDataClass.  This was not a breaking issue just a matter of keeping things nice and tidy.

Support of Required and Display Name Attributes (v2.0.0+)

Now adds the Required and friendly Display Name data annotation attributes for properties based upon camel casing and underscores for spacing between words.
I hope this helps save you some time!

Known Issues and Work Arounds:

  1. Null Reference Exception:
    1. Issue
      1. When using Entity Framework 5 or 6 the necessary entity framework reference is not added to the T4 template so a null reference exception is produced
    2. Work Around
      1. Add the following line as line 3 of the T4 Template making sure to have the correct path to the dll
      2. <#@ assembly name="c:\Projects\MyProject\bin\EntityFramework.dll" #>
      3. Make sure that any usuage of Entity.EntityState is strongly typed to System.Data.Entity.EntityState (should be line 55 after above line is added)
  2. The letters ID are being removed regardless of location in text.  For example: OverrideID becomes Overre
    1. Correction is coming soon but you can adjust the logic manually in the FormatPropertyName function in the t4 template. 
    2. The corrected logic is as follows and will included in the next version
if(str.Substring(str.Length -2,2).ToUpper() == "ID" && str.Length > 2)
{
str = str.Substring(0, str.Length -2).Replace("_"," " );
}

Next version will include corrections for all of these issues.  If you discover other issues please contact us and let us know so we can get them fixed.


*** All Content is provided As Is ***

No comments:

Post a Comment