Site Meter
 
 

MvcScaffolding: Overriding the T4 Templates

This blog post is part of a series about the MvcScaffolding NuGet package:

  1. Introduction: Scaffold your ASP.NET MVC 3 project with the MvcScaffolding package
  2. Standard usage: Typical use cases and options
  3. One-to-Many Relationships
  4. Scaffolding Actions and Unit Tests
  5. This post: Overriding the T4 templates
  6. Creating custom scaffolders
  7. Scaffolding custom collections of files

Previous posts in this series have shown how you can use MvcScaffolding’s built-in features to handle a range of CRUD scenarios, as well as quickly generate actions, view models, views, and unit test stubs using the included templates. But what if you want to do something different?

In this post and over the next two, I’ll show you how you can:

  • Change the code that the built-in scaffolders generate by overriding the T4 templates they use
  • Scaffold completely different types of things by creating your own new, custom scaffolders with arbitrary PowerShell logic
  • Combine multiple built-in and custom scaffolders to generate whole structures of code files that implement useful functionality

Overriding the T4 Templates

Note: This post assumes you’ve already installed the MvcScaffolding package. If not, see the earlier posts in this series for an introduction.

The simplest form of customisation is overriding the T4 templates. For example, if you want to change what data access code is generated, you can supply your own templates that produce code based on NHibernate, or Mongo, or whatever, instead of Entity Framework which is the default.

To get started, you first need to know which existing T4 template you want to override. You can find this out either by:

  • Looking in <yourSolutionDir>\packages\<scaffolderPackage>\tools to see the structure of scaffolders and templates
  • Or, by running the scaffolder whose output you want to change and passing the –Verbose flag so it tells you which templates it’s using
  • Or, just by looking at the following table to see the built-in ones:
Scaffolder name Template name What it’s used for
DbContext DbContext Empty data context class
DbContext DbContextEntityMember Entity set property used for each model type added to the data context class (e.g., DbSet<YourModel> properties)
Repository Repository Repository interface and default concrete implementation
Action Action Action method (Note: only used when generating standalone actions. Not used by controller scaffolder)
Action ActionPost As above, for actions that handle POST requests
Action ViewModel View model used by scaffolded actions
ActionUnitTest TestClass Empty unit test class
ActionUnitTest TestMethod Unit test method stub
View Create, _CreateOrEdit, Delete, Details, Edit, Empty, Index MVC view for the corresponding view type
(Note: CreateOrEdit has no leading underscore if you’re generating ASPX views, because that’s a Razor convention)
Controller ControllerWithContext Complete MVC controller with inline data access code
Controller ControllerWithRepository Complete MVC controller that uses repositories for data access

Next, run the special “CustomTemplate” scaffolder to create a template override. The syntax is: “Scaffold CustomTemplate scaffoldername templatename”. For example, if you want to override the repository template, the scaffolder name is “repository”, and so is the template name, so you run:

SNAGHTML2d9deaf9_thumb[1]

This adds a new CustomScaffolders folder into your project which contains the template override:

image_thumb[2]

Now all you have to do is edit that file, Repository.cs.t4, using T4 syntax to define the code you want to generate. You can use T4’s <#= … #> blocks to evaluate parameter values supplied by the scaffolder to insert things like the repository name, the model type, the model primary key property name, and so on. The file’s initial contents acts as an example you can modify.

For example, if you wanted repositories implemented as static in-memory collections, instead of being backed by a SQL database, you could set up the first few lines of the class template as follows:

/// <summary>
/// A dummy in-memory repository for <#= modelName #> entities. Its data will be reset each time you restart the application.
/// </summary>
public class <#= modelName #>Repository : I<#= modelName #>Repository
{
    private readonly static Dictionary<<#= primaryKeyProperty.Type.AsString #>, <#= modelName #>> InMemoryCollection = new Dictionary<<#= primaryKeyProperty.Type.AsString #>, <#= modelName #>>();
 
    public IQueryable<<#= modelName #>> All
    {
        get { return InMemoryCollection.Values.AsQueryable(); }
    }

… and of course edit the rest of the template to read/write data in InMemoryCollection too.

Using Your Custom Template

You don’t have to do anything special to use the custom template. Just the fact that it’s there in your project means it will override the default one. So, next time you run “Scaffold Repository SomeEntity” (or scaffold a controller using the –Repository switch), it will use your template.

Of course, this means it’s easy to share: just commit your /CodeTemplate folder into source control, and then your template becomes a standard for everyone working on your project.

A runnable example

For reference, see the downloadable example project that includes a complete “in-memory collection repository” template. Try it out by generating a controller with repository for the provided StockItem model:

Scaffold Controller StockItem -Repository

Then, you can compile and run the application, navigate to the URL /StockItems, and add/edit/delete items in the in-memory collection.

If you’d like to do something a little more interesting, how about adapting the repository template further, to generate code that reads/writes data using NHibernate or Mongo or some other data store?

18 Responses to MvcScaffolding: Overriding the T4 Templates

  1. Pingback: The Morning Brew - Chris Alcock » The Morning Brew #829

  2. Thanks for getting these out! I will definitely be giving it a try. somehow, you snuck these out while I had stopped checking every day. i won’t let that mistake happen twice.

  3. Hi Steve,

    Regarding scaffolding our views, where can we find documentation on what properties are available to us?

    i.e.

    What else is there for us?
    is there a ?

  4. Bah, Model.ViewDataTypeName exists, what else is there? Where is the documentation?

    Not sure what’s up with the commenting here.

  5. Pingback: MvcScaffolding Enhancement - DisplayAttribute Support - Naughton Futilities

  6. João Attila

    Hi Steve,

    I think that table is not correct when u say about ActionUnitTest.

    Only worked when uses Scaffold CustomTemplate UnitTest TestMethod/TestClass.

    Using ActionUnitTest it didnt work.

    Thanks for this post! Was Helpfull!

    Hugs!

    João Attila

  7. Pingback: MvcScaffolding: Standard Usage - Steve Sanderson’s blog - As seen on YouTube™

  8. Buddy Stein

    Steve, great work, I use the scaffolds all the time.

    Question, Is there a way to just generate a single view (ie: index) of a controller that uses a repository and dbcontext?

    I haven’t found a syntax to generate a single view with a model.

  9. Dipakdave

    Steve

    How can I override T4 template for view ???

  10. Graeme

    Has anyone implemented custom template to create ViewModel with AutoMapper mappings and also to popluate the ViewModel properties etc?

  11. Eamon

    I’ve been thrilled to find this excellent post about custom T4′s for MvcScaffolding and have followed the instructions carefully. I have custom templates for generating AspxViews (Create, CreateOrEdit, Delete, Edit, Index), and Repository which all work great.
    However I cannot get the customised ControllerWithRepository template to work. Running -verbose when scaffolding indicates that it found the template but it seems like it ignores it and uses the default! Could this be a minor flaw for this one template? Any ideas?

    Here’s the output:
    Found template ‘ControllerWithRepository’ at ‘C:\dev\…off_my_projects_root…\CodeTemplates\Scaffolders\MvcScaffolding.Controller\ControllerWithRepository.cs.t4′
    Added controller Controllers\ProductsController.cs

  12. Chris

    Thanks for this. I can’t explain how happy I am with this.

    I’m having the same issue as Eamon. The ControllerWithRepository seems to be ignored.

    Any ideas?

    Thanks,

    Chris

  13. Biergarten

    Can the t4 templates be opened/edited from Visaul Studio 2010. I keep getting an error “The operation could not be completed”

  14. Jon

    help!
    The view-file created by Scaffold doesn’t have the utf-8 BOM signature?
    Steps:
    1. I created a custom template Index.cs.t4.
    2. Filled some unicode character. e.g: “新建”.
    3. Create view: Scaffold Views Users Index -Force -ModelType User.

    Then, the characters is unreadable which was in template.But, Some characters are displaying well which are querying from the database.

    I must change each file created by Scaffold. Open it, Save as UTF-8.

    If I unchecked the option “Auto-detect UTF-8 encoding without signature” at “Visual Studio Tools-> Text Editor->General”. VS couldn’t open the file created by Scaffold

  15. You'll find

    There are certainly a lot of details like this take into consideration. That is an excellent point to create up. I provide thoughts over as general inspiration GuildWars2 Necromancer nevertheless clearly you will find questions such as the one you mention where it is important will be working in honest good faith. I don? t understand if best practices have come about around such things as that, but More than likely that your job is clearly referred to as a reasonable game. Both boys and girls feel the actual impact of only a moment’s satisfaction, for the rest of their own lives.

  16. Pablo

    Hi All, does anyone know how to customize the filename of a view? instead of “Create.cshtml” I’d like something like “WhateverIWant.cshtml”.

    Thanks!

  17. I’m with Graeme..
    Has anyone implemented custom template to create ViewModel with AutoMapper mappings and also to popluate the ViewModel properties etc?