June 2014

Volume 29 Number 6

ASP.NET MVC : Override the Default Scaffold Templates

Jonathan Waldman

The mundane tasks of writing routine create, retrieve, update and delete operations against a data store is aptly conveyed by the oft-used acronym CRUD. Microsoft provides a helpful scaffolding engine, powered by T4 templates, that automates creating basic CRUD controllers and views for models in ASP.NET MVC applications that use the Entity Framework. (There are also WebAPI and MVC without Entity Framework scaffolders currently available.)

Scaffolds generate pages that are navigable and usable. They generally relieve you of the monotony involved in constructing CRUD pages. However, scaffolded results offer such limited functionality that you soon find yourself tweaking the generated controller logic and views to suit your needs.

The peril in doing this is that scaffolding is a one-way process. You can’t re-scaffold your controller and views to reflect changes in a model without overwriting your tweaks. Therefore, you have to exercise vigilance in tracking which modules you’ve customized, so you can know which models you can safely re-scaffold and which ones you can’t.

In a team environment, this vigilance is difficult to enforce. To top it off, the edit controller displays most model properties on the Edit view, thereby potentially exposing sensitive information. It blindly model binds and persists all view-submitted properties, which increases the risk of a mass-assignment attack.

In this article, I’ll show you how to create project-specific customizations of the T4 templates that power the ASP.NET MVC Entity Framework CRUD scaffolding subsystem. Along the way, I’ll show you how to extend the controller’s Create and Edit postback handlers so you can inject your own code between postback model binding and data-store persistence.

To address mass-assignment concerns, I’ll create a custom attribute that gives you full control over the model properties that should persist and which ones shouldn’t. Then I’ll add another custom attribute that lets you display a property as a read-only label on the Edit view.

After this, you’ll have unprecedented control over your CRUD pages and how your models are displayed and persisted while reducing your app’s exposure to attacks. Best of all, you’ll be able to leverage these techniques for all the models in your ASP.NET MVC projects, and safely regenerate controllers and views as your models change.

Project Setup

I developed this solution using Visual Studio 2013 Ultimate, ASP.NET MVC 5, Entity Framework 6, and C# (the techniques discussed are also compatible with Visual Studio 2013 Professional, Premium and Express for Web and Visual Basic .NET). I created two solutions for download: The first is the Baseline Solution, which you can use to start with a working project and manually implement these techniques. The second is the Complete Solution, which includes all of the improvements discussed herein.

Each solution contains three projects: one for the ASP.NET MVC Web site, one for entity models and T4-scaffold functions, and one for the data context. The solutions’ data context points to a SQL Server Express database. In addition to the dependencies already mentioned, I added Bootstrap using NuGet to theme the scaffolded views.

The scaffold subsystem is installed during Setup when you check the Microsoft Web Developer Tools setup option. Subsequent Visual Studio service packs will update the scaffold files automatically. You can get any updates to the scaffold subsystem released between Visual Studio service packs in the latest Microsoft Web Platform Installer, which you can download from bit.ly/1g42AhP.

If you have any issues using the code download accompanying this article, ensure you have its latest version and carefully read the ReadMe.txt file. I’ll update that as needed.

Define the Business Rules

To illustrate the full workflow involved in generating CRUD views and to reduce distractions, I’m going to work with a very simple entity model called Product.

public class Product
{
  public int ProductId { get; set; }
  public string Description { get; set; }
  public DateTime? CreatedDate { get; set; }
  public DateTime? ModifiedDate { get; set; }
}

By convention, MVC understands that ProductId is the primary key, but it has no idea I have special requirements regarding the CreatedDate and ModifiedDate properties. As their names imply, I want CreatedDate to convey when the product in question (represented by ProductId) was inserted into the database. I also want ModifiedDate to convey when it was last modified (I’ll use UTC date-time values).

I’d like to display the ModifiedDate value on the Edit view as read-only text (if the record has never been modified, the ModifiedDate will equal the CreatedDate). I don’t want to display the CreatedDate on any of the views. I also don’t want the user to be able to supply or modify these date values, so I don’t want to render any form controls that collect input for them on the Create or Edit views.

In an effort to make these values attack-proof, I want to be sure their values aren’t persisted on postback, even if a clever hacker is able to supply them as form fields or querystring values. Because I consider these business logic layer rules, I don’t want the database to have any responsibility for maintaining these column values (for instance, I don’t want to create any triggers or embed any table-column definition logic).

Explore the CRUD Scaffold Workflow

Let’s first examine the default scaffold’s function. I’ll add a controller by right-clicking the Web project’s Controllers folder and choosing Add Controller. This launches the Add Scaffold dialog (see Figure 1).

The MVC 5 Add Scaffold Dialog
Figure 1 The MVC 5 Add Scaffold Dialog

The entry “MVC 5 Controller with views, using Entity Framework” is the one I’ll use because it scaffolds the CRUD controller and views for a model. Select that entry and click Add. The next dialog gives you a number of options that end up as parameters for the T4 templates it subsequently transforms (see Figure 2).

The Add Controller Dialog
Figure 2 The Add Controller Dialog

Enter ProductController as the controller name. Keep “Use the async controller actions” checkbox unchecked for the sake of this discussion (async operations are beyond the scope of this article). Next, choose the Product model class. Because you’re using the Entity Framework, you’ll need a data context class. Classes that inherit from System.Data.Entity.DbContext appear in the dropdown, so select the correct one if your solution uses more than one database context. With respect to the view options, check “Generate views” and “Use a layout page.” Leave the layout page textbox empty.

When you click Add, several T4 templates are transformed to provide the scaffolded results. This process generates code for a controller (ProductController.cs), which is written to the Web project’s Controllers folder, and five views (Create.cshtml, Delete.cshtml, Details.cshtml, Edit.cshtml, and Index.cshtml), which are written to the Web project’s Views folder. At this point, you have a working controller and all the CRUD views you’ll need to manage the data in the Product entity. You can begin using these Web pages right away, starting with the index view.

You’ll likely want your CRUD pages to look and behave similarly for all the models in your project. Using T4 templates to scaffold the CRUD pages helps enforce this consistency. This means you should resist the temptation to directly modify controllers and views. Instead you should modify the T4 templates that generate them. Follow this practice to ensure your scaffolded files are ready to use with no further modifications.

Examine the Controller’s Shortcomings

While the scaffold subsystem gets you up and running rather quickly, the controller it generates has several shortcomings. I’ll show you how to make some improvements. Look at the scaffolded controller action methods that handle the Create and Edit in Figure 3.

Figure 3 The Scaffolded Controller Action Methods for Create and Edit

public ActionResult Create(
  [Bind(Include="ProductId,Description,CreatedDate,ModifiedDate")] 
  Product product)
{
  if (ModelState.IsValid)
  {
    db.Products.Add(product);
    db.SaveChanges();
    return RedirectToAction("Index");
  }
  return View(product);
}
public ActionResult Edit(
  [Bind(Include="ProductId,Description,CreatedDate,ModifiedDate")] 
  Product product)
{
  if (ModelState.IsValid)
  {
    db.Entry(product).State = EntityState.Modified;
    db.SaveChanges();
    return RedirectToAction("Index");
  }
  return View(product);
}

The Bind attribute for each method explicitly includes every property on the Product model. When an MVC controller model binds all model properties after postback, it’s called mass assignment. This is also called overposting and it’s a serious security vulnerability. Hackers can exploit this vulnerability because there’s a subsequent SaveChanges invocation on the database context. This ensures the model gets persisted to the data store. The controller template the CRUD scaffold system in MVC 5 uses generates mass-assignment code by default for the Create and Edit action postback methods.

Another consequence of mass assignment happens if you choose to decorate certain properties on the model so they aren’t rendered to the Create or Edit view. Those properties will be set to null after model binding. (See “Use Attributes to Supress Properties on CRUD Views,” which contains attributes you can use to specify whether you should render scaffolded properties to generated views.) To illustrate, I’ll first add two attributes to the Product model:

public class Product
{
  public int ProductId { get; set; }
  public string Description { get; set; }
  [ScaffoldColumn(false)]
  public DateTime? CreatedDate { get; set; }
  [Editable(false)]
  public DateTime? ModifiedDate { get; set; }
}

When I re-run the scaffold process using Add Controller, as discussed earlier, the [Scaffold(false)] attribute ensures the CreatedDate won’t appear on any views. The [Editable(false)] attribute ensures the ModifiedDate will appear on the Delete, Details, and Index views, but not the Create or Edit views. When properties aren’t rendered to a Create or Edit view, they won’t appear in the postback’s HTTP request stream.

This is problematic because the last chance you have to assign values to model properties in these MVC-powered CRUD pages is during postback. So if a property postback value is null, that null value is going to be model-bound. Then the model is going to be persisted to the data store when SaveChanges is executed on the data context object. If this is done in the Edit postback action method, that property will be replaced with a null value. This effectively deletes the current value in the data store.

In my example, the value held by CreatedDate in the data store would be lost. In fact, any property not rendered to the Edit view will cause the data store’s value to be overwritten with null. If the model property or the data store doesn’t allow assignment of a null value, you’ll get an error on postback. To overcome these shortcomings, I’ll modify the T4 template that’s responsible for generating the controller. 

Override the Scaffold Templates

To modify how the controller and views are scaffolded, you have to modify the T4 templates that generate them. You can modify the original templates, which will globally affect scaffolding across all Visual Studio projects. You could also modify project-specific copies of the T4 templates, which will only affect the project into which the copies are placed. I’ll do the latter.

The original T4 scaffold templates are located in the %programfiles%\Microsoft Visual Studio 12.0\Common7\IDE\Extensions\Microsoft\Web\Mvc\Scaffolding\Templates folder. (These templates depend on several .NET assemblies, located in the %programfiles%\­Microsoft Visual Studio 12.0\Common7\IDE\Extensions\Microsoft\Web Tools\Scaffolding folder.) I’ll focus on the specific templates that scaffold the Entity Framework CRUD controller and views. These are summarized in Figure 4.

Figure 4 The T4 Templates That Scaffold Entity Framework CRUD Controller and Views

Scaffold Templates Sub-Folder Name

Template File Name

(.cs for C#; .vb for Visual Basic .NET)

Generates This File

(.cs for C#; .vb for Visual Basic .NET)

MvcControllerWithContext

Controller.cs.t4

Controller.vb.t4

Controller.cs

Controller.vb

MvcView

Create.cs.t4

Create.vb.t4

Create.cshtml

Create.vbhtml

MvcView

Delete.cs.t4

Delete.vb.t4

Delete.cshtml

Delete.vbhtml

MvcView

Details.cs.t4

Details.vb.t4

Details.cshtml

Details.vbhtml

MvcView

Edit.cs.t4

Edit.vb.t4

Edit.cshtml

Edit.vbhtml

MvcView

Index.cshtml

Index.vbhtml

Index.cshtml

Index.vbhtml

To create project-specific templates, copy the files you want to override from the original T4 scaffold folder to a folder in the ASP.NET MVC Web project called CodeTemplates (it must have this exact name). By convention, the scaffold subsystem first looks in the MVC project’s CodeTemplates folder for a template match.

For this to work, you must precisely replicate the specific sub-folder names and file names you see in the original templates folder. I’ve copied the T4 files I plan to override from the CRUD for the Entity Framework scaffold subsystem. See my Web project’s CodeTemplates in Figure 5.

The Web Project’s CodeTemplates
Figure 5 The Web Project’s CodeTemplates

I also copied Imports.include.t4 and ModelMetadataFunctions.cs.include.t4. The project requires these files in order to scaffold the views. Also, I copied only the C# (.cs) versions of the files (if you’re using Visual Basic .NET, you’ll want to copy the files that include .vb in the file name). The scaffolding subsystem will transform these project-specific files, instead of their global versions.

Extend the Create and Edit Action Methods

Now that I have project-specific T4 templates, I can modify them as needed. First, I’ll extend the controller’s Create and Edit action methods so I can inspect and modify the model before it’s persisted. To keep the code the template generates as generic as possible, I don’t want to add any model-specific logic to the template. Instead, I want to call an external function bound to the model. This way, the controller’s Create and Edit are extended while they simulate polymorphism on the model. To this end, I’ll create an interface and call it IControllerHooks:

namespace JW_ScaffoldEnhancement.Models
{
  public interface IControllerHooks
  {
    void OnCreate();
    void OnEdit();
  }
}

Next, I’ll modify the Controller.cs.t4 template (in the CodeTemplates\­MVCControllerWithContext folder) so its Create and Edit postback action methods call the model’s OnCreate and OnEdit methods, respectively, if the model has implemented IControllerHooks. The controller’s Create action postback method is shown in Figure 6 and its Create action postback method is shown in Figure 7.

Figure 6 Extended Version of the Controller’s Create Action Postback Method

public ActionResult Create(
  [Bind(Include="ProductId,Description,CreatedDate,ModifiedDate")] 
  Product product)
{
  if (ModelState.IsValid)
  {
    if (product is IControllerHooks) { 
      ((IControllerHooks)product).OnCreate(); 
    }
    db.Products.Add(product);
    db.SaveChanges();
    return RedirectToAction("Index");
  }
  return View(product);
}

Figure 7 Extended Version of the Controller’s Edit Action Postback Method

public ActionResult Edit(
  [Bind(Include="ProductId,Description,CreatedDate,ModifiedDate")] 
  Product product)
{
  if (ModelState.IsValid)
  {
    if (product is IControllerHooks) { 
      ((IControllerHooks)product).OnEdit(); 
    }
    db.Entry(product).State = EntityState.Modified;
    db.SaveChanges();
    return RedirectToAction("Index");
  }
  return View(product);
}

Now, I’ll modify the Product class so it implements IController­Hooks. Then I’ll add the code I want to execute when the controller calls OnCreate and OnEdit. The new Product model class is shown in Figure 8.

Figure 8 Product Model That Implements IControllerHooks to Extend the Controller

public class Product : IControllerHooks
{
  public int ProductId { get; set; }
  public string Description { get; set; }
  public DateTime? CreatedDate { get; set; }
  public DateTime? ModifiedDate { get; set; }
  public void OnCreate()
  {
    this.CreatedDate = DateTime.UtcNow;
    this.ModifiedDate = this.CreatedDate;
  }
  public void OnEdit()
  {
    this.ModifiedDate = DateTime.UtcNow;
  }
}

Admittedly, there are many ways to implement this “extension” logic, but by using this one-line modification to the Create and Edit methods of the controller template, I can now modify the product model instance after model binding, but before persistence. I can even set the value of model properties that aren’t published to the Create and Edit views.

You’ll observe the model’s OnEdit function doesn’t set a value for CreatedDate. If CreatedDate isn’t rendered to the Edit view, then it’s going to be overwritten with a null value after the controller’s Edit action method persists the model when it calls SaveChanges. To prevent this from happening, I’m going to need to make some further modifications to the controller template.

Enhance the Edit Action Method

I’ve already mentioned some of the problems associated with mass assignment. One way to modify the model-binding behavior is to modify the Bind attribute so it excludes properties not to bind. In practice, however, this approach can still result in writing null values to the data store. A better strategy involves additional programming, but the payoff is well worth the effort.

I’m going to use the Entity Framework Attach method to attach the model to the database context. I can then track the entity entry and set the IsModified property as needed. To drive this logic, I’ll create a new class module called CustomAttributes.cs in the JW_Scaffold­Enhancement.Models project (see Figure 9).

Figure 9 The New Class Module CustomAttributes.cs

using System;
namespace JW_ScaffoldEnhancement.Models
{ 
  public class PersistPropertyOnEdit : Attribute
  {
    public readonly bool PersistPostbackDataFlag;
    public PersistPropertyOnEdit(bool persistPostbackDataFlag)
    {
      this.PersistPostbackDataFlag = persistPostbackDataFlag;
    }
  }
}

I’ll use this attribute to indicate the properties I don’t want to be persisted to the data store from the Edit view (undecorated properties will have an implicit [PersistPropertyOnEdit(true)] attribute). I’m interested in preventing the CreatedDate property from being persisted, so I’ve added the new attribute to only the CreatedDate property of my Product model. The newly decorated model class is shown here:

public class Product : IControllerHooks
{
  public int ProductId { get; set; }
  public string Description { get; set; }
  [PersistPropertyOnEdit(false)]
  public DateTime? CreatedDate { get; set; }
  public DateTime? ModifiedDate { get; set; }
}

Now I’ll need to modify the Controller.cs.t4 template so it honors the new attribute. When enhancing a T4 template, you’ve got a choice as to whether to make changes within the template or external to the template. Unless you’re using one of the third-party template-editor tools, I’d advocate placing as much code as possible in an external code module. Doing so provides a pure C# canvas (rather than one interspersed with T4 markup) within which you can focus on code. It also aids testing and gives you a way to incorporate your functions into your broader test-harness efforts. Finally, due to some shortcomings in how assemblies are referenced from a T4 scaffold, you’ll experience fewer technical issues getting everything wired up.

My Models project contains a public function called GetPropertyIsModifiedList, which returns a List<String> I can iterate over to generate the IsModified settings for the assembly and type passed. Figure 10 shows this code in the Controller.cs.t4 template.

T4 Template Code Used To Generate an Improved Controller Edit Postback Handler
Figure 10 T4 Template Code Used To Generate an Improved Controller Edit Postback Handler

In GetPropertyIsModifiedList, shown in Figure 11, I use reflection to gain access to the provided model’s properties. Then I iterate across them to determine which ones are decorated with the PersistPropertyOnEdit attribute. You’ll most likely want to persist most of the properties on your models, so I constructed the template code to set a property’s IsModified value to true by default. This way, all you need to do is add [PersistPropertyOnEdit(false)] to the properties you don’t want to persist.

Figure 11 The Model Project ScaffoldFunctions.GetPropertyIsModifiedList Static Function

static public List<string> GetPropertyIsModifiedList(string ModelNamespace, 
  string ModelTypeName, 
  string ModelVariable)
{
  List<string> OutputList = new List<string>();
  // Get the properties of the model object
  string aqn = Assembly.CreateQualifiedName(ModelNamespace + 
    ", Version=1.0.0.0,
    Culture=neutral, PublicKeyToken=null", ModelNamespace + "." + 
    ModelTypeName);
  // Get a Type object based on the Assembly Qualified Name
  Type typeModel = Type.GetType(aqn);
  // Get the properties of the type
  PropertyInfo[] typeModelProperties = typeModel.GetProperties();
  PersistPropertyOnEdit persistPropertyOnEdit;
  foreach (PropertyInfo propertyInfo in typeModelProperties)
  {
    persistPropertyOnEdit = 
      (PersistPropertyOnEdit)Attribute.GetCustomAttribute(
      typeModel.GetProperty(propertyInfo.Name), typeof(PersistPropertyOnEdit));
    if (persistPropertyOnEdit == null)
    {
    OutputList.Add(ModelVariable + "Entry.Property(e => e." +
      propertyInfo.Name + ").IsModified = true;");
    }
    else
    {
    OutputList.Add(ModelVariable + "Entry.Property(e => e." +
      propertyInfo.Name + ").IsModified = " +
      ((PersistPropertyOnEdit)persistPropertyOnEdit).
      PersistPostbackDataFlag.ToString().ToLower() + ";");
    }
  }
  return OutputList;
}

The revised controller template generates a reconceived Edit postback action method, shown in Figure 12. My GetPropertyIsModifiedList function generates portions of this source code.

Figure 12 The Newly Scaffolded Controller Edit Handler

if (ModelState.IsValid)
{
  if (product is IControllerHooks) 
  {
   ((IControllerHooks)product).OnEdit(); 
  }
  db.Products.Attach(product);
  var productEntry = db.Entry(product);
  productEntry.Property(e => e.ProductId).IsModified = true;
  productEntry.Property(e => e.Description).IsModified = true;
  productEntry.Property(e => e.CreatedDate).IsModified = false;
  productEntry.Property(e => e.ModifiedDate).IsModified = true;
  db.SaveChanges();
  return RedirectToAction("Index");
}

Use Attributes to Suppress Properties on CRUD Views

ASP.NET MVC offers only three attributes that provide some control over whether a model’s properties are rendered to the scaffolded views (see Figure A). The first two attributes do the same thing (although they reside in different namespaces): [Editable(false)] and [ReadOnly(true)]. These will cause the decorated property to not be rendered to the Create and Edit views. The third, [ScaffoldColumn(false)], causes the decorated property not to appear on any of the rendered views.

Figure A The Three Attributes That Prevent Properties from Rendering

Model Metadata Attribute Attribute Namespace Views Affected What Happens
  None None No additional attributes causes only normal results.

[Editable(false)]

[ReadOnly(true)]

Editable:

System.ComponentModel.DataAnnotations

ReadOnly:

System.ComponentModel

Create

Edit

Decorated model property not rendered.
[ScaffoldColumn(false)] System.ComponentModel.DataAnnotations

Create

Delete

Details

Edit

Index

Decorated model property not rendered.

Customize a View

Sometimes you’ll want to display a value on the edit view that you don’t want users to edit. The ASP.NET MVC-provided attributes don’t support this. I’d like to see the ModifiedDate on the Edit view, but I don’t want the user to think it’s an editable field. To implement this, I’ll create another custom attribute called DisplayOnEditView in the CustomAttributes.cs class module, shown here:

public class DisplayOnEditView : Attribute
{
  public readonly bool DisplayFlag;               
  public DisplayOnEditView(bool displayFlag)
  {
    this.DisplayFlag = displayFlag;
  }
}

This lets me decorate a model property so it renders as a label on the Edit view. Then I’ll be able to show the ModifiedDate on the Edit view without worrying that someone can tamper with its value during postback.

Now I can use that attribute to further decorate the Product model. I’ll place the new attribute on the ModifiedDate property. I’ll use [Editable(false)] to ensure it won’t appear on the Create view and [DisplayOnEditView(true)] to ensure it appears as a label on the Edit view:

public class Product : IControllerHooks
{
  public int ProductId { get; set; }
  public string Description { get; set; }
  [PersistPropertyOnEdit(false)]
  [ScaffoldColumn(false)]
  public DateTime? CreatedDate { get; set; }
  [Editable(false)]
  [DisplayOnEditView(true)]
  public DateTime? ModifiedDate { get; set; }
}

Finally, I’ll modify the T4 template that generates the Edit view so it honors the DisplayOnEditView attribute:

HtmlForDisplayOnEditViewAttribute =
  JW_ScaffoldEnhancement.Models.ScaffoldFunctions.
  GetHtmlForDisplayOnEditViewAttribute(
  ViewDataTypeName, property.PropertyName,
  property.IsReadOnly);

And I’ll add the GetHtmlForDisplayOnEditViewAttribute function to the ScaffoldFunctions class as shown in Figure 13.

The GetHtmlForDisplayOnEditViewAttribute function returns Html.EditorFor when the attribute is false and Html.Display­TextFor when the attribute is true. The Edit view will display the ModifiedDate as a label and all other non-key fields as editable textboxes, shown in Figure 14.

Figure 13 ScaffoldFunctions.GetHtmlForDisplayOnEditViewAttribute Static Function to Support the Custom DisplayOnEditViewFlag Attribute

static public string GetHtmlForDisplayOnEditViewAttribute(
  string ViewDataTypeName, string PropertyName, bool IsReadOnly)
{
  string returnValue = String.Empty;
  Attribute displayOnEditView = null;
  Type typeModel = Type.GetType(ViewDataTypeName);
  if (typeModel != null)
  {
    displayOnEditView =
    (DisplayOnEditView)Attribute.GetCustomAttribute(typeModel.GetProperty(
    PropertyName), typeof(DisplayOnEditView));
    if (displayOnEditView == null)
    {
      if (IsReadOnly)
      { returnValue = String.Empty; }
      else
      { returnValue = "@Html.EditorFor(model => model." + 
          PropertyName + ")"; }
    }
    else
    {                         
      if (((DisplayOnEditView)displayOnEditView).DisplayFlag == true)
      { returnValue = "@Html.DisplayTextFor(model => model." + 
          PropertyName + ")"; }
      else
      { returnValue = "@Html.EditorFor(model => model." + 
        PropertyName + ")"; }
    }
  }
  return returnValue;
}

Figure 14 Edit View Showing a Read-Only ModifiedDate Field

Wrapping Up

I’ve just scratched the surface of what you can accomplish with the scaffolding subsystem. I focused on the scaffolds that provide a CRUD control and views for the Entity Framework, but there are other scaffolds available to generate code for other types of Web pages and Web API actions.

If you’ve never worked with T4 templates, customizing existing templates is a great way to start. Although the templates I discussed here are launched from menus with the Visual Studio IDE, you can create custom T4 templates and transform them whenever necessary. Microsoft provides a good starting point at bit.ly/1coB616. If you’re looking for something more advanced, I recommend Dustin Davis’ course bit.ly/1bNiVXU.

At this time, Visual Studio 2013 doesn’t include a robust T4 editor. In fact, it doesn’t offer syntax highlighting or IntelliSense. Fortunately, there are some add-on products that do.  Check out the Devart T4 editor (bit.ly/1cabzOE) and the Tangible Engineering T4 Editor (bit.ly/1fswFbo).


Jonathan Waldman is an experienced software developer and technical architect. He has been working with the Microsoft technology stack since its inception. He has worked on several high-profile enterprise projects and participated in all aspects of the software development lifecycle. He’s a member of the Pluralsight technical team and continues to develop software solutions and educational materials. Reach him at jonathan.waldman@live.com.

Thanks to the following Microsoft technical expert for reviewing this article: Joost de Nijs
Joost de Nijs is a Program Manager on the Azure Developer Experience team at Microsoft, working on Web Developer Tooling.  Currently he is focused on the Web Scaffolding and NuGet Package management feature areas, with previous work on the Windows Azure Java Client Libraries and the Windows Azure Developer Center.