Twitter About Home

MvcScaffolding: Creating custom scaffolders

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

Published Apr 7, 2011
  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. Overriding the T4 templates
  6. This post: Creating custom scaffolders
  7. Scaffolding custom collections of files

Intro

If you only ever want to generate controllers, actions, repositories, and the other item types built into MvcScaffolding, it’s enough just to customise the T4 templates for them. But what if you want to generate something different, for example configuration files, build scripts, CSS files, JavaScript files, or something else? Or what if you want to generate combinations of multiple interrelated items?

You can create a custom scaffolder that uses arbitrary PowerShell logic. It can render T4 templates (multiple ones if you want), with the result being output:

  • As a new file in your project
  • Or, as a new code block inserted into an existing class

Or, your PowerShell logic can use Visual Studio’s “code model” API to manipulate files and code elements in other arbitrary ways.

Example: Scaffolding jQuery Plugins

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

Let’s say your team uses jQuery plugins all the time. Every separate bit of client-side functionality is implemented as a separate jQuery plugin. So, to speed this up and to gain better consistency, you want to make a scaffolder that generates the outline of a jQuery plugin. To get started, run the CustomScaffolder scaffolder, giving the name jQueryPlugin for your new scaffolder:

SNAGHTML2dbba9a7_thumb1

Yes, CustomScaffolder is a scaffolder that generates other scaffolders. I find this pleasing in a recursive kind of way.

This adds a CodeTemplates folder to your project, containing files for the new scaffolder:

image_thumb5

As you can see, we’ve got two files:

  • A PowerShell script (.ps1), where we can put arbitrary logic to decide what templates get rendered and where the output goes. By default, it renders a T4 template and uses the output to create a new file called ExampleOutput in the root of your project.
  • A T4 template (.t4), i.e., the thing that the default .ps1 file renders. By default this generates a simple C#/VB class (depending on your project type).

If you want to see this working, you can run the custom scaffolder right away:

Scaffold jQueryPlugin

This will generate a new class file, ExampleOutput.cs, in the root folder of your project. That’s really just to show you how it works. We don’t really want that, so don’t run the new scaffolder yet, or if you already have done, delete ExampleOutput.cs.

Making it do something useful

Here’s the design for our jQueryPlugin scaffolder:

  • It will take two parameters: PluginName (mandatory), and HasOptions (an optional switch that modifies the JavaScript code we generate).
  • It will render a T4 template, passing those parameter values to it. The template will produce the outline of a jQuery Plugin JavaScript file.
  • The output will create a new file, /Scripts/jQuery/jQuery.pluginname.js

To actually implement this, you either need a passing familiarity with PowerShell, or at least the willingness to play around with the default script and try to modify it to suit your requirements. It’s a bit out of scope for me to try to teach PowerShell in this blog post, so let’s skip to the completed implementation. Here’s my finished jQueryPlugin.ps1 file:

[T4Scaffolding.Scaffolder(Description = "Creates a jQuery Plugin code file")][CmdletBinding()]
param(
    [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)][string]$PluginName,
    [switch]$HasOptions,
    [string]$Project,
    [string]$CodeLanguage,
    [string[]]$TemplateFolders,
    [switch]$Force = $false
)
 
$outputPath = "Scripts\jQueryPlugins\jQuery.$PluginName.js"
 
Add-ProjectItemViaTemplate $outputPath -Template jQueryPluginTemplate `
    -Model @{ PluginName = $PluginName; HasOptions = $HasOptions.IsPresent } `
    -SuccessMessage "Added jQuery plugin at {0}" `
    -TemplateFolders $TemplateFolders -Project $Project -CodeLanguage $CodeLanguage -Force:$Force
 
Write-Host "---"
Write-Host "To reference your new jQuery plugin, copy the following script reference into your layout:"
Write-Host "<script src=`"`@Url.Content(`"~/$($outputPath.Replace("\", "/"))`")`" type=`"text/javascript`"></script>" -ForegroundColor DarkRed -BackgroundColor Gray
Write-Host "---"

I appreciate this may be a bit alien if you’ve never seen PowerShell before, but it’s not actually so bad:

  • The first few lines define metadata about the scaffolder itself – its description, and a definition of the parameters it takes (including saying which are mandatory/optional).
  • Add-ProjectItemViaTemplate is a cmdlet built into T4Scaffolding. It renders a T4 template (in this example, one called “jQueryPluginTemplate”) and creates a new file in your project containing the output (in this case, in the folder “Scripts\jQueryPlugins\”). You can pass whatever data you want from the PS1 script to the T4 template (in this example, we just pass the PluginName and HasOptions parameter values). See the end of this blog post for more info about T4Scaffolding’s built-in cmdlets.
  • Write-Host emits text into the console itself. In this example, we’re using it to supply useful information to the developer – an example

Next, we need the T4 template that defines the JavaScript code we want to generate. Here’s my finished jQueryPluginTemplate.t4 file. If you’ve written jQuery plugins before, this will probably look very familiar:

<#@ Template Language="C#" HostSpecific="True" Inherits="DynamicTransform" #>
// ----
// <#= Model.PluginName #> jQuery plugin
// ----
(function ($) {
    $.fn.<#= Model.PluginName #> = function (<# if(Model.HasOptions) { #>options<# } #>) {
<# if(Model.HasOptions) { #>
        var allOptions = $.extend({
            // TODO: Put default option values here
        }, options);
 
<# } #>
        return this.each(function () {
 
            var $this = $(this);
            // TODO: Add code here to operate on $this
 
        });
    };
})(jQuery);

Running the custom scaffolder

Now, you can invoke your custom scaffolder to generate jQuery plugins from the console. There’s full tab-completion support, so developers can auto-complete not just the name of your scaffolder (jQueryPlugin), but also the names of the custom parameters it takes.

SNAGHTML2dd907cd_thumb1[3]

This will generate a JavaScript source file at Scripts\jQueryPlugins\jQuery.reverseText.js, containing:

// ----
// reverseText jQuery plugin
// ----
(function ($) {
    $.fn.reverseText = function (options) {
        var allOptions = $.extend({
            // TODO: Put default option values here
        }, options);
 
        return this.each(function () {
 
            var $this = $(this);
            // TODO: Add code here to operate on $this
 
        });
    };
})(jQuery);

Once you’ve referenced this script file (e.g., by copy & pasting the example

$(".someClass").reverseText();

A runnable example

Download the demo project, which contains the jQueryPlugin custom scaffolder. You can run it from the Package Manager console as follows:

Scaffold jQueryPlugin somePluginName             # Like this...
Scaffold jQueryPlugin somePluginName –HasOptions # ... or like this

Useful Scaffolding Cmdlets

In the preceding example, I demonstrated the use of Add-ProjectItemViaTemplate, a PowerShell cmdlet included in the core T4Scaffolding package (installed automatically when you install MvcScaffolding).

There are many other useful cmdlets included in T4Scaffolding that you can use from your custom scaffolders, for example to:

  • Render T4 templates
  • Inspect and modify files in your solution’s projects
  • Inspect and modify code elements in your classes
  • Detect primary keys and 1:many relations on entity classes
  • Interact with source control bindings
  • … or merely to pluralise words.

For a list of examples, see this wiki page on CodePlex.

Conclusion

With a bit of PowerShell-fu (or a bit of copy-paste-existing-examples-fu), you can make your own scaffolder that:

  • Takes a custom set of parameters
  • Renders a custom set of T4 templates
  • Sends the output to a custom set of locations in your project or in existing classes

Once you’ve made it, it’s easy to share with colleagues: just commit your /CodeTemplates folder into source control, and then anyone working on your project will be able to run your scaffolder

In the next post, I’ll present a slightly bigger example that does output multiple files, and produces a different type of controller with an Ajax-powered grid in its view.

READ NEXT

MvcScaffolding: Overriding the T4 Templates

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

Published Apr 6, 2011