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 ***

Tuesday, January 14, 2014

RazorJS: The solution to using Razor in external JavaScript Files

If you are like me, I prefer to separate all JavaScript from the Views or Webpages. The difficulty in doing this is the lack of a method to use Razor Syntax to inject more fault tolerant urls, data and other Razor goodies. Yes, it can be achieved with out Razor by declaring the variables in a small JavaScript but I want complete separation not partial.

I did a little digging and found that there is a project called RazorJS. This project does exactly what I am looking to do with a few limitations. This project allows you to use the full Razor syntax with in the JavaScript and allows data models to be passed in so it can be references as part of the Razor. The limitations that I have found at the current moment is the lack of support for the ViewBag, ViewData, and TempData to be referenced in the Model. The solution is to add these to the strongly typed view model or as a dictionary.

For example of how to implement RazorJS and documentation refer to http://john.katsiotis.com/blog/razorjs---write-razor-inside-your-javascript-files

To install RazorJS via Nuget use Install-Package RazorJS. Details on the Nuget package can be found at http://www.nuget.org/packages/RazorJS/

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