NuTemplates

Monday, December 15, 2014

How to make solution templates with NuGet packages

Visual studio templates capabilities are quite limited. Yes, you can save some work but you basically can only do projects and files with heavy limitations. What about if we put some executable code in to the equation?

The Problem

Within our organization (NuGetting Soft), there is a typical VS Solution that developers need to create quite often. It has 3 projects:

Interface with all public stuff, interfaces, service parameter and return types.

Domain with the actual logic and all private implementation stuff.

Tests with all unit tests.

More than just saving people time, we want all the solutions to be arranged in a particular manner with assemblies and namespaces named accordingly to the specific domain being implemented. If some team wants to build something for Human Resources we want: NuGettingSoft.HumanResources.Interface for the interface, NuGeetingSoft.HumanResources for the domain and HumanResources.Tests for the unit tests.

NuGetting

NuGet packages are an easy and clean way to deploy libraries. I recently discover you can put some code in there as well. Powershell scripts, which are quite powerful and not hard at all to get started with.

You’d need to install NuGet and make sure it is accessible from the command line. Then go ahead and create a VS Solution with a Project and open the Package Manager Console (PM). We see something like this:

Not very useful but I promise it will grow. This Powershell file will be executed the first time a package is installed and every time the solution is loaded afterwards. Powershell is the language we can use to program custom operations in NuGet packages.

We’ve replaced the project Ids with tokens (e.g: %Interface.ProjectId%). Project names and paths could be replaced too, but for simplicity we won’t. I recommend not touching the Ids on the left, no idea what they are.

I seriously hope I’ve done a good job and previous code wouldn’t need much explanation. The idea is to iterate by all files and call Apply-Template on each of them dropping the result on a temporary folder. Later move that folder content into $destinationPath and clear all our footsteps.

This one works over the pipeline. It iterates all keys in $tokens, regex’em to the input and replaces them by their value if found.

Add projects to solution

After all templates have been applied we just need to add each of the projects to the solution. Since there are dependencies we need to specify the order. Now that we have only 3 projects, it can be done by hand, but perhaps an automatic process can be used if that number grows.

Here we use a $dte, and object available from PM. All interactions with VS can be done thru it, even activating menu items. Read about the dte here.

Last but not least

Uninstall-Package $package.Id

Weird, right? The thing is Init.ps1 will be executed every time the solution is opened. We don’t want the templates applying everyday, potencially erasing all work done. Besides, this package provides nothing once installed. Other techniques to detect that templates have been applied could be used instead…and even allow more templating with package updates. But for now, let’s keep it simple.

Here we also used another object $package this one is a NuGet.OptimizedZipPackage, you can read more about it here. It has zillions of properties and methods. You’ll need to navigate the hierarchy or reflect compiled NuGet to get the whole list. I’ve found these to be very useful:

You can get your hands into the $project if the package would have been installed into a project. You would find info about it here.

Wrap it up

That was pretty much of the heavy artillery, there are some more helper functions out there but they are not worthy to be shown here. I’ve extracted all these functions into a library file: Template-Tools.ps1, as I’am likely to need them again. That will actually trigger a warning when NuGet packing by saying that it’s an Unrecognized PowerScript file, just pay no attention to it.

The Solution

Our new Omega team has been appointed to build the Domain for our Human Resources department. Sam, one of their developers, goes and creates an empty solution named HumanResources:

Then he runs on the PM:

Install-Package NuGettingSoft.SolutionTemplate

When the process ends, he gets:

Love Automation…Don’t you?

Conclusions

NuGet packages give an organization a powerful scaffolding tool which could greatly improve uniformity and productivity. A little bit of imagination on top of it could take you anywhere. Tomorrow you might be generating very large shells with no sweat.

As usual, with power comes responsibility. You will be deploying executable code. Think the developer installing your package might be running VS as Administrator.