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?

Scaffolding Actions and Unit Tests with MvcScaffolding

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. This post: Scaffolding Actions and Unit Tests
  5. Overriding the T4 templates
  6. Creating custom scaffolders
  7. Scaffolding custom collections of files

So, if you’ve read any of my previous posts about MvcScaffolding, you’ll know that you can use it for “CRUD” scenarios: i.e., making create, read, update, delete pages so that users can enter and edit data. Scaffolding and CRUD go together so often that people get the impression that scaffolding is only about CRUD. Well, it’s not. You can do a lot more with scaffolding.

In this post I’ll show you how to use MvcScaffolding to quickly add action methods to controllers (along with their views and view models), and to scaffold unit test stubs for them.

Hang on,” you might be thinking, “I can already add action methods and unit tests. I just type them into Visual Studio.” Yes, yes, of course you can. But this way is faster, and lets you set up and share your own templates for them. Like snippets, but with more command-line smarts.

Installing or Updating MvcScaffolding

First, open an ASP.NET MVC 3 project, open the Package Manager Console, and then install the MvcScaffolding package, being sure to get version 0.9.8 or later:

Install-Package MvcScaffolding

If your project already has a version of MvcScaffolding older than 0.9.8, update it like this:

Update-Package MvcScaffolding

Note: If you’re updating from an older version, this will prompt you to restart Visual Studio before continuing the installation. Obey it, or badness will happen! So, after restarting VS, run “Install-Package MvcScaffolding” again. This time it won’t prompt you to restart VS.

Scaffolding Actions

To add a ContactMe action to your HomeController, run the following scaffolding command:

Scaffold Action Home ContactMe

What will happen? HomeController will have a new method:

public class HomeController : Controller
{
    // ... existing code not affected ...
 
    public ViewResult ContactMe()
    {
        return View();
    }
}

… and there’ll be a view for ContactMe at /Views/Home/ContactMe.cshtml.

Excellent. That was slightly quicker than adding the action and view by hand. But I almost always want to pass a view model from my actions to their views, so there’s a clean, strongly-typed way of transferring action-specific data. No problem. There’s a switch for that.

Delete the ContactMe action and view (or use the –Force) switch, and rescaffold as follows:

Scaffold Action Home ContactMe –WithViewModel

What happens?

SNAGHTML3efc96dd

This time it’s added an action that uses a view model:

public class HomeController : Controller
{
    // ... existing code not affected ...
 
    public ViewResult ContactMe()
    {
        return View(new ContactMeViewModel {
            // Populate properties here
        });
    }
}

… and created a view model at /Models/ContactMeViewModel.cs:

public class ContactMeViewModel
{
    // Add properties here
}

… and made the view, /Views/Home/ContactMe.cshtml strongly typed for the ContactMeViewModel class.

Or, if you prefer the view model class to be called ContactInfo, use the –ViewModel parameter instead of the –WithViewModel switch:

Scaffold Action Home ContactMe -ViewModel ContactInfo

If there’s already a ContactInfo class, it will use it (wherever it is), or if not it will create a new one in /Models.

Now you can go ahead and add suitable properties to the view model class and reference them in both the action and the view. In total, this saves a few more seconds compared to creating all those files by hand.

Scaffolding Post-handling Actions

OK, so you’ve created your basic action. Maybe you’ve added some properties to the view model, like this:

public class ContactInfo
{
    [Required] public string Name { get; set; }
    [Required] public string EmailAddress { get; set; }
}

… and edited the view, /Views/Home/ContactMe.cshtml to display a form:

@model ActionScaffoldingExample.Models.ContactInfo
@{ ViewBag.Title = "ContactMe"; }
 
<h2>Contact Me</h2>
<p>Give us your contact details, and we'll, well, contact you. Obviously.</p>
 
@using (Html.BeginForm()) {
    @Html.EditorForModel()
    <input type="submit" />
}

Next, you need some action to receive the posted data. You could create it by hand like normal. Or, you could scaffold it, like this:

Scaffold Action Home ContactMe -ViewModel ContactInfo -Post

This adds the following action method (without affecting your existing code):

[HttpPost, ActionName("ContactMe")]
public ActionResult ContactMePost(ContactInfo contactinfo)
{
    if (ModelState.IsValid) {
        return RedirectToAction("Index");
    } else {
        return View(contactinfo);
    }
}

You can go ahead and edit this to put in some code to send an email, save the data to a database, or whatever. But right away you’ve got the basics of handling form posts, slightly quicker than typing it out by hand.

Scaffolding Unit Test Stubs

If you’re writing unit tests, you probably need all the help you can get with making the process more streamlined. The benefits of unit testing are high, but so are the costs, so let’s try to reduce the costs a bit.

Do you already have a unit test project in your solution called “{YourMvcProjectName}.Test” or “{YourMvcProjectName}.Tests”? If not, you can add one by right-clicking your solution name in Solution Explorer, choosing Add->New Project, and choosing “Test Project” (use “Search Installed Templates” if you can’t find that). To follow the naming convention, if your main project is called MySuperApp, call the test project MySuperApp.Test or MySuperApp.Tests. Finally, add a reference from the new test project to System.Web.Mvc and to your main MVC application project.

Now you can run the following scaffolding command:

Scaffold UnitTest Home ContactMe

What will this do?

  • If you don’t already have a HomeControllerTest.cs class file in your test project, it will create one
  • Then it will add a unit test stub for your ContactMe action:
    [TestClass]
    public class HomeControllerTest
    {
        [TestMethod]
        public void ContactMeTest()
        {
            // Arrange
            var controller = new HomeController();
 
            // Act
            var viewResult = controller.ContactMe();
            var viewModel = viewResult.Model;
 
            // Assert
            // Assert.AreEqual("expected value", viewModel.SomeProperty);
            Assert.Inconclusive(); // Todo: Make assertions, then remove this line
        }
    }

Add some assertions, remove the “Assert.Inconclusive” line (which is there to make sure you don’t just leave the stub code as-is and think you’ve actually got a passing test) and you’re away.

If you will be writing assertions about property values on your view model class, you can optionally specify the view model class name. Either write:

Scaffold UnitTest Home ContactMe –WithViewModel

… to use the default view model name, or

Scaffold UnitTest Home ContactMe –ViewModel ContactInfo

… to specify a custom view model class name. If you do either of these, the unit test stub will be set up to require the ViewResult to have a Model value of the right type:

// Act
var viewResult = controller.ContactMe();
var viewModel = (ContactInfo)viewResult.Model;

Now you can easily add assertions based on this view model type.

Scaffolding Unit Test Stubs for Post-handling Actions

If you want a unit test to specify how your post-handling action should behave, just specify the post-handling action by name. For example,

Scaffold UnitTest Home ContactMePost

This will generate the following test stub:

[TestMethod]
public void ContactMePostTest()
{
    // Arrange
    var controller = new HomeController();
 
    // Act
    var actionResult = controller.ContactMePost(null);
 
    // Assert
    Assert.Inconclusive(); // Todo: Make assertions, then remove this line
}

If you want to write a test to specify how the action handles particular ContactInfo parameter values, construct a ContactInfo instance in the test and replace the “null” in “controller.ContactMePost(null)” with your instance variable. Of course, this will not test model binding (including validation that happens during model binding), as that’s a separate concern.

Notice that this time, the generated code doesn’t include anything to do with a ViewResult. Why is this? The template for test methods inspects the return type of your action method, and produces different code depending on that type.

  • If your method returns a ViewResult, the test will automatically extract the Model value (cast to your view model type, if given), so you can write assertions against it
  • If your method returns a RedirectToRouteResult, the test will automatically grab the RouteData values so you can write assertions about them
  • If your method returns a general ActionResult or something else, as in the last example, the test will just obtain the action result instance and it’s up to you what to do with it.

You can customize this logic by customizing the template if you want (details below).

And what if you don’t want to use MSTest, but would rather use NUnit or something else? That’s also a matter of customizing the templates.

Scaffolding Actions *with* Unit Tests in One Shot

If you want both the action and a test stub for it in a single command, try this:

Scaffold MvcScaffolding.ActionWithUnitTest Home SomethingElse -WithViewModel

This one command gives you an action called SomethingElse, a view model class called SomethingElseViewModel, a view (strongly-typed), a unit test class, and a unit test method stub (set up to work with the generated view model class). Surely that is saving you several seconds at least.

If you wanted to establish the standard that all scaffolded actions should have unit tests, write this:

Set-DefaultScaffolder Action MvcScaffolding.ActionWithUnitTest

Now, “Scaffold Action” will map to the MvcScaffolding.ActionWithUnitTest scaffolder, instead of mapping to MvcScaffolding.Action as it does by default.

Customizing the Templates

I’m about to write a whole post about customizing the templates, but in the meantime, here’s a sneak preview. Try any of the following:

Scaffold CustomTemplate MvcScaffolding.Action Action
Scaffold CustomTemplate MvcScaffolding.Action ActionPost
Scaffold CustomTemplate MvcScaffolding.Action ViewModel
Scaffold CustomTemplate MvcScaffolding.ActionUnitTest TestClass
Scaffold CustomTemplate MvcScaffolding.ActionUnitTest TestMethod

Then edit the T4 templates that appear in your project’s /CodeTemplates/Scaffolders folder.

Then run the scaffolding commands again (remember to pass –Force if you want to overwrite existing files).

See the difference.

To share your templates overrides with others on your team, simply commit them into source control.

Conclusion

For people who enjoy the power of the Package Manager Console command line, scaffolding actions and unit tests is a fast and customizable way of adding arbitrary code to your project.

In a future post, I’ll show how to create entirely new scaffolders of your own that apply custom PowerShell logic and can add any combination of files and class members, rather than just customizing T4 templates.

MvcScaffolding: One-to-Many Relationships

This 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. This post: One-to-Many Relationships
  4. Scaffolding Actions and Unit Tests
  5. Overriding the T4 templates
  6. Creating custom scaffolders
  7. Scaffolding custom collections of files

Recently I’ve been adding features at a frantic pace, the most significant of which is support for relationships between entities. This means you can quickly create Create-Read-Update-Delete (CRUD) interfaces with drop-down lists, for example to set which “category” a “product” is in, or who is the “manager” or an “employee”.

Installing or Upgrading MvcScaffolding

The features I describe in this post are available in MvcScaffolding 0.9.4 or later. If you already have a previous version installed (find out by typing Get-Package into the NuGet console), you can upgrade it as follows:

Update-Package MvcScaffolding

After upgrading, you must restart Visual Studio, otherwise the old version will still be loaded into the VS appdomain, and bad things will happen. Restart Visual Studio now!

If you’ve never installed MvcScaffolding into your project, install it by entering the following into the NuGet Package Manager Console:

Install-Package MvcScaffolding

Defining simple relations between model classes

I’m going to continue the tutorial in the introductory post, which assumes you’ve already installed created the following model class:

public class Team
{
    public int TeamId { get; set; }
    [Required] public string Name { get; set; }
    public string City { get; set; }
    public DateTime Founded { get; set; }
}

Now I’d like to define another model class, Player. Each Player is associated with a team:

public class Player
{
    public int PlayerId { get; set; }
    public string Name { get; set; }
 
    // Having a property called <entity>Id defines a relationship
    public int TeamId { get; set; }
}

Simply having the TeamId property on Player is enough for both MvcScaffolding and EF Code First to realise there’s a 1:many relationship. Actually MvcScaffolding supports two conventions for defining relations – this is the simple one; I’ll explain the alternative later.

Note that defining TeamId as a non-nullable int, it’s mandatory. Each player must be in a team. If you wanted the relationship to be optional, use a nullable link property instead (i.e., public int? TeamId { get; set; }).

If you scaffold your UI now, by executing the following commands…

Scaffold Controller Team -Force
Scaffold Controller Player

(note the –Force parameter tells scaffolding to overwrite anything you already had for Team)

… then you can go to the URL /Teams and create, read, update, delete teams:

image

… and then you can go to the URL /Players and do the same for players. When you’re creating or editing a player, you’ll get a drop-down list to choose a team:

image

So, how does this work? How can the Edit action know what teams to offer in the dropdown? MvcScaffolding has created a PlayersController in which the Create/Edit actions send a list of PossibleTeams to the view to be rendered in a dropdown:

// This is in PlayersController
public ActionResult Create()
{
    ViewBag.PossibleTeams = context.Teams;
    return View();
}

If you wanted to filter the available teams in some way, you could easily edit this and put a .Where(team => somecondition) clause on the end. Scaffolding isn’t supposed to generate a finished application; it just gives you a useful starting point very quickly!

Showing relationships on Index and Details views

Right now, the Index and Details views don’t show any information about relationships. The list of teams doesn’t tell you about players:

image

… and the list of players doesn’t tell you about teams:

image

The reason no relations are shown is that neither the Team nor Player class has a property to hold instances of the related entities, so there’s nowhere to get the information from. We can improve the situation by telling Player to have a property that holds its Team:

public class Player
{
    public int PlayerId { get; set; }
    public string Name { get; set; }
    public int TeamId { get; set; }
 
    public virtual Team Team { get; set; } // This is new
}

… and by telling Team to have a property that holds its Players:

public class Team
{
    public int TeamId { get; set; }
    [Required] public string Name { get; set; }
    public string City { get; set; }
    public DateTime Founded { get; set; }
 
    public virtual ICollection<player> Players { get; set; } // This is new
}

Notice that both of these new properties are marked virtual. This lets Entity Framework use its Lazy Loading feature so the associated entities will be fetched as needed, and spares you having to write code to fetch them in your controller. I’ll talk more about this in a moment.

Now if you were to scaffold the UI with models like this, by issuing the following commands:

Scaffold Controller Team -Force
Scaffold Controller Player -Force

… then you’d find the list of teams now states how many players are associated with each:

image

…and the list of players now states which team each player belongs to:

image

Similarly, if you go onto the other views (Details, Delete, etc.), you’ll see the related model objects displayed there too:

image

This is probably exactly what you expected to see. But pause for a moment and consider: when we want to display a related model object in a grid or in a details view, how do we know how to represent that other object as a string? There could be many properties on “Team” – how do we know which one to display in the Players grid?

The answer is that MvcScaffolding uses its own conventions to go looking for a property with a likely name: Name, Title, Surname, Subject, Count. If there’s no matching property, we fall back on using ASP.NET MVC’s Html.DisplayTextFor helper. If you don’t agree with the property it chose, you can either:

  • Put a [DisplayColumn] attribute on your model class. For example, by putting [DisplayColumn("SomeProperty")] right before “public class Team…” and then rerunning the scaffolder, you’ll cause it to choose the property SomeProperty, if there is one.
  • Or, modify the T4 template to specify your own conventions (see the forthcoming post for info about customising T4 templates)
  • Or, just edit the generated views and change them! This is the easiest and best choice normally. Remember, scaffolding just gives you a quick starting point. It’s up to you to work on the code to meet all your own application’s requirements.

Eager Loading and SELECT N+1

If you’ve used ORMs before, then when you heard me talk about lazy loading you probably caught the scent of possible blood. If the Player’s “Team” property is marked virtual and hence lazy loaded, then when we display the grid of Player entities, does rendering each row cause us to issue yet another SQL query to fetch the Team for that Player? That, by the way, is called a “SELECT N+1” problem and leads to serious performance issues.

Fortunately, when the scaffolder generates your Index actions, it anticipates this and instructs EF to “eager load” all the related entities up front in a single SQL query. Example:

// This is on PlayersController
public ViewResult Index()
{
    return View(context.Players.Include(player => player.Team).ToList());
}

If your model has multiple relations, they will all be eager loaded for the grid. However, we don’t eager load for the other actions (Edit, Create, etc.) because there’s no scale problem with those – you’re only loading a single entity, and the code is easier to understand if we use normal lazy loading in those cases.

It also works when you’re generating repository classes, too, by the way. If you were to build everything with repositories like this:

Scaffold Controller Team -Repository -Force
Scaffold Controller Player -Repository -Force

… then your controllers would have constructors that receive all of the repositories they need, e.g.:

public PlayersController(ITeamRepository teamRepository, IPlayerRepository playerRepository)
{
    this.teamRepository = teamRepository;
    this.playerRepository = playerRepository;
}

… and the Index actions would still eager-load relations, using a slightly different syntax that the repository interface understands:

// This is on PlayersController
public ViewResult Index()
{
    return View(playerRepository.GetAllPlayers(player => player.Team));
}

You can thank Scott Hanselman for this feature of doing eager loading automatically. He hassled me about it yesterday, so here it is :)

Defining more complex relations between model classes

Depending on what data access technology you’re using, there may be many possible ways of defining how models are related together. If you’re using EF Code First, for example, you could be using its fluent configuration interface, which means writing code with statements like “someEntity.HasOptional(x => x.Players).WithForeignKey(x => x.TeamId).CascadeDelete()” and so on.

MvcScaffolding doesn’t know about all of that. For one thing, fluent configuration exists only at runtime (and scaffolding works at design time), and for another, you might be using any data access technology with its own configuration system. You can still use fluent configuration or anything else; just don’t expect scaffolding to know about it.

Instead, MvcScaffolding supports two simple and broadly applicable conventions that will work fine with most data access technologies, including EF.

(1) You can define a simple parent relation to the model class <SomeEntity> by adding a property called <SomeEntity>Id, as you’ve already seen:

public class Player
{
    public int PlayerId { get; set; }
    public string Name { get; set; }
 
    // This links Player to Team
    public int TeamId { get; set; }
}

Note that if you also have a Team property on Player (as in the code earlier), EF recognizes this convention and populates Team with the entity specified by TeamId. Scaffolding, however, doesn’t need to know or care about this: it just displays Team information in Player views because that property is there.

(2) You can define a complex parent relation by adding a property called <Anything>Id, plus another property called <Anything> that defines the type of the relation. For example, you could make Team objects reference other Team objects, or multiple Person objects:

public class Team
{
    public int TeamId { get; set; }
    // ... other Team properties go here
 
    // Each Team has an optional "next opponent" which is another Team
    public int? NextOpponentId { get; set; }
    [ForeignKey("NextOpponentId")] public virtual Team NextOpponent { get; set; }
 
    // Each Team also has a required Manager and Administrator, both of which are people
    public int ManagerId { get; set; }
    public int AdministratorId { get; set; }
    [ForeignKey("ManagerId")] public virtual Person Manager { get; set; }
    [ForeignKey("AdministratorId")] public virtual Person Administrator { get; set; }
}

The [ForeignKey] attributes are there for EF’s benefit, so it understands what we’re doing. If you’re using another data access technology, you may not need them, or you may need something else. MvcScaffolding doesn’t know or care about those them.

Of course, you don’t have to follow these conventions if you don’t want, but these are the ways that MvcScaffolding knows how to generate typical CRUD UI respecting the associations.

What else is new

There are a lot of other smaller improvements in MvcScaffolding 0.9.4. For example,

  • Based on your feedback, controller names are now pluralized by default (e.g., you get PeopleController rather than PersonController for a model of type Person, unless you explicitly enter PersonController as the controller name when scaffolding)
  • There’s now a single CreateOrEdit partial shared by both the Create and Edit views
  • Support for master pages in ASPX views is better
  • It runs on NuGet 1.1 now
  • You no longer need to compile (or even save!) your code before scaffolding it. Because it now uses the VS CodeModel API, compilation is irrelevant. However, make sure your code is syntactically valid when you scaffold, otherwise you’ll get a big spew of errors.

In fact, there are loads of improvements so I won’t list them all – see the source code log if you want to know everything!

In the next post I’ll show how you can customise the T4 templates and possibly even how to create completely new scaffolders of your own.

Reporting issues and giving feedback

By now, MvcScaffolding has a lot of nontrivial functionality and when you’re first starting to use it, you’ll inevitably run into something that doesn’t do what you expected. Personally, I’m still kind of new to EF, so I usually fail to configure it property. Or I make a change and can’t work out why it’s not appearing, then remember I haven’t re-run the scaffolder yet.

By all means please post brief comments about the design or feature ideas here on this blog, but note that it’s not the ideal place for involved discussions. Also, apologies in advance for slow replies: I’ll be away for the next week, and won’t reply to anything in that time :)