Create your own Visual Studio extensions with SideWaffle & TemplateBuilder

Pieter van der Westhuizen, a professional freelance web & mobile developer and founder of Coalition Software.
Search for a command to run...

Pieter van der Westhuizen, a professional freelance web & mobile developer and founder of Coalition Software.
A recent requirement came up for configurable dynamic forms in a mobile application. There are a few dynamic form packages for Flutter, but I wanted a bit more control over the schema and behavior of the form. Here follows my attempt at creating dyna...

If you've ever written a mobile app with Flutter that integrates with an API, then you'll know that there are a lot of model objects that get passed between the app and the API. JSON Serialization in Flutter can also take a fair amount of boilerplate...

Back in May 2020, Microsoft announced a new feature for Azure Blob Storage called Blob Index. Essentially, this enables you to add key/value tags to your Blob objects and be able to query said Blob objects without having to use a separate service lik...

In my last post, "Using AWS Cognito with Xamarin Forms", I showed how to authenticate with Amazon Cognito using Xamarin Forms and the Xamarin.Essentials Web Authenticator. In this post, we'll go through the process of using the AWS Cognito Hosted UI ...

In this post, I'll show you how to quickly and easily set up user authentication for your Xamarin Forms app using Amazon Cognito. AWS Cognito is a user identity management solution by Amazon. It is a really easy way to add authentication to your appl...

The SideWaffle Template pack for Visual Studio is great, but did you know you can also create your own template packs using the TemplateBuilder nuget package?
In this post I’ll guide you through a step-by-step guide on how you can create your own Visual Studio extensions. It’s not that hard, but you do need to keep your wits about you. So without further ado, let’s get started.
Update: SideWaffle has been updated to make it even easier to create your own extensions – without having to export the template first. Take a look at Sayed’s video to see how.
Before you can build a template, you need a project on which the template is based. For this example, I’ve built an empty ASP.Net MVC template that uses the Foundation Framework. We’ll use this project to create a Visual Studio template that makes it easy to create an ASP.Net MVC site based on the Foundation Framework from Zurb.
The project layout looks like this in Visual Studio:

There’s not much to the project, it contains the necessary Foundation assets (CSS and JavaScript files) and we have a Home controller with one view and a Layout file.
With the project in place, we need to export it as a template. Do this by selecting Export Template from the Visual Studio File menu.

We want to create a Project template, so on the first screen of the “Export Template Wizard”, select the Project Template radio button.

Click Next and on the next screen complete the Template name and Template description fields and select an Icon Image as well as a Preview Image for the template. We do not want to import the template into Visual Studio, so deselect Automatically import the template into Visual Studio. Keep the Display an explorer window on the output files folder checkbox selected.

Click Finish. An Windows Explorer window open the folder where the template was exported to. In my case the location is : C:\Users\Pieter\Documents\Visual Studio 2013\My Exported Templates

Extract the zip file to a location. We’ll get back to the extracted files a bit later.
Next, we need to create a new VSIX Project in Visual Studio. You’ll find the project template under Extensibility. If you do not see the project template, you probably do not have the Visual Studio SDK installed. You can download it here.

After the project is created, Visual Studio will display a window, where you can edit certain properties of the VSIX.

Notice that the source.extension.vsixmanifest file contains all the necessary project information and its made up of XML mark-up. Our XML in the file currently looks something like the following (Your GUIDs will differ):
source.extension.vsixmanifest
<?xml version="1.0" encoding="utf-8"?>
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
<Metadata>
<Identity Id="FoundationMVC..fb6d38b2-622c-4be2-a2f7-bde181a5fe9b" Version="1.0" Language="en-US" Publisher="Mythical Man Moth" />
<DisplayName>ASP.Net MVC Foundation Site</DisplayName>
<Description xml:space="preserve">ASP.Net MVC Site with the Zurb Foundation Framework</Description>
<Icon>icon.png</Icon>
<PreviewImage>preview.png</PreviewImage>
</Metadata>
<Installation>
<InstallationTarget Id="Microsoft.VisualStudio.Pro" Version="[12.0]" />
</Installation>
<Dependencies>
<Dependency Id="Microsoft.Framework.NDP" DisplayName="Microsoft .NET Framework" d:Source="Manual" Version="[4.5,)" />
</Dependencies>
</PackageManifest>
The next step we need to take is to add the TemplateBuilder Nuget package to our project. To do this open the Package Manager Console and enter the following command, followed by enter:
Install-Package TemplateBuilder –Pre
If all goes well, you should see the following output in the Package Manager Console:
Package Manager Console
PM> Install-Package TemplateBuilder -Pre
Installing 'TemplateBuilder 1.0.3.45-beta'.
Successfully installed 'TemplateBuilder 1.0.3.45-beta'.
Adding 'TemplateBuilder 1.0.3.45-beta' to FoundationVSIX.
Successfully added 'TemplateBuilder 1.0.3.45-beta' to FoundationVSIX.
*********** Adding template-builder
Adding item template asset tag to .vsixmanifest file C:DevelopmentFoundationExtensionFoundationVSIXFoundationVSIXsource.extension.vsixmanifest
Adding project template asset tag to .vsixmanifest file C:DevelopmentFoundationExtensionFoundationVSIXFoundationVSIXsource.extension.vsixmanifest
TemplateBuilder has been installed into project [C:DevelopmentFoundationExtensionFoundationVSIXFoundationVSIXFoundationVSIX.csproj]
Open the source.extension.vsixmanifest file and you’ll notice that two items has been added to the Assets element. This tells TemplateBuilder where it can find the Item and Project templates for the VSIX package. The full code for the source.extension.vsixmanifest file now looks like (New items are bolded):
source.extension.vsixmanifest
<?xml version="1.0" encoding="utf-8"?>
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
<Metadata>
<Identity Id="FoundationMVC..fb6d38b2-622c-4be2-a2f7-bde181a5fe9b" Version="1.0" Language="en-US" Publisher="Mythical Man Moth" />
<DisplayName>ASP.Net MVC Foundation Site</DisplayName>
<Description xml:space="preserve">ASP.Net MVC Site with the Zurb Foundation Framework</Description>
<Icon>icon.png</Icon>
<PreviewImage>preview.png</PreviewImage>
</Metadata>
<Installation>
<InstallationTarget Id="Microsoft.VisualStudio.Pro" Version="[12.0]" />
</Installation>
<Dependencies>
<Dependency Id="Microsoft.Framework.NDP" DisplayName="Microsoft .NET Framework" d:Source="Manual" Version="[4.5,)" />
</Dependencies>
<Assets>
<Asset Type="Microsoft.VisualStudio.ItemTemplate" Path="OutputItemTemplates" />
<Asset Type="Microsoft.VisualStudio.ProjectTemplate" Path="OutputProjectTemplates" />
</Assets>
</PackageManifest>
Before we can add the template files we extracted earlier. We need to add a few more things to our project. First, create a new folder called ProjectTemplates

Next, add new SideWaffle Project Template files to the ProjectTemplates folder. If you do not see the item template under Extensibility > SideWaffle it means you do no have SideWaffle installed.

The item template will add the following to the ProjectTemplates folder:
The Solution Explorer should look like the following:

Next, navigate to the folder to which you’ve extracted the exported template we’ve created earlier and copy all the files.

Switch back to Visual Studio and right-click on the ProjectTemplates folder and select Open folder in File Explorer

Paste the copied files in the folder

When switching back to Visual Studio, you won’t see the project files, unless you click the Show All Files button on the Solution Explorer toolbar. This is fine, you do not need to include the files inside the project. You can include the files, it will make no difference.

Next, open the MyTemplate.vstemplate file (This will be in the exported project template folder). And copy the TemplateContent element and all its child elements. Open the Csharp.vstemplate file and replace its TemplateContent element with the one you’ve just copied. The full mark-up for the Csharp.vstemplate file follows:
Csharp.vstemplate
<VSTemplate Version="3.0.0" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005" Type="Project">
<TemplateData>
<Name>MVC Zurb Foundation</Name>
<Description>Zurb Foundation MVC Project</Description>
<ProjectType>CSharp</ProjectType>
<ProjectSubType></ProjectSubType>
<SortOrder>1000</SortOrder>
<CreateNewFolder>true</CreateNewFolder>
<ProvideDefaultName>true</ProvideDefaultName>
<LocationField>Enabled</LocationField>
<EnableLocationBrowseButton>true</EnableLocationBrowseButton>
<Icon>sw-file-icon.png</Icon>
<!– Indicates how many parent folders this item template should appear in –>
<NumberOfParentCategoriesToRollUp>1</NumberOfParentCategoriesToRollUp>
</TemplateData>
<TemplateContent>
<Project TargetFileName="FoundationProject.csproj" File="FoundationProject.csproj" ReplaceParameters="true">
<Folder Name="App_Data" TargetFolderName="App_Data" />
<Folder Name="App_Start" TargetFolderName="App_Start">
<ProjectItem ReplaceParameters="true" TargetFileName="BundleConfig.cs">BundleConfig.cs</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="RouteConfig.cs">RouteConfig.cs</ProjectItem>
</Folder>
<Folder Name="Controllers" TargetFolderName="Controllers">
<ProjectItem ReplaceParameters="true" TargetFileName="HomeController.cs">HomeController.cs</ProjectItem>
</Folder>
<Folder Name="css" TargetFolderName="css">
<ProjectItem ReplaceParameters="true" TargetFileName="app.css">app.css</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="foundation.css">foundation.css</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="foundation.min.css">foundation.min.css</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="normalize.css">normalize.css</ProjectItem>
</Folder>
<ProjectItem ReplaceParameters="true" TargetFileName="Global.asax">Global.asax</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="Global.asax.cs">Global.asax.cs</ProjectItem>
<Folder Name="img" TargetFolderName="img" />
<Folder Name="js" TargetFolderName="js">
<Folder Name="foundation" TargetFolderName="foundation">
<ProjectItem ReplaceParameters="true" TargetFileName="foundation.abide.js">foundation.abide.js</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="foundation.accordion.js">foundation.accordion.js</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="foundation.alert.js">foundation.alert.js</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="foundation.clearing.js">foundation.clearing.js</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="foundation.dropdown.js">foundation.dropdown.js</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="foundation.interchange.js">foundation.interchange.js</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="foundation.joyride.js">foundation.joyride.js</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="foundation.js">foundation.js</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="foundation.magellan.js">foundation.magellan.js</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="foundation.offcanvas.js">foundation.offcanvas.js</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="foundation.orbit.js">foundation.orbit.js</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="foundation.reveal.js">foundation.reveal.js</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="foundation.tab.js">foundation.tab.js</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="foundation.tooltip.js">foundation.tooltip.js</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="foundation.topbar.js">foundation.topbar.js</ProjectItem>
</Folder>
<ProjectItem ReplaceParameters="true" TargetFileName="foundation.min.js">foundation.min.js</ProjectItem>
<Folder Name="vendor" TargetFolderName="vendor">
<ProjectItem ReplaceParameters="true" TargetFileName="custom.modernizr.js">custom.modernizr.js</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="fastclick.js">fastclick.js</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="jquery.autocomplete.js">jquery.autocomplete.js</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="jquery.cookie.js">jquery.cookie.js</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="jquery.js">jquery.js</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="modernizr.js">modernizr.js</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="placeholder.js">placeholder.js</ProjectItem>
</Folder>
</Folder>
<Folder Name="Models" TargetFolderName="Models" />
<ProjectItem ReplaceParameters="true" TargetFileName="packages.config">packages.config</ProjectItem>
<Folder Name="Properties" TargetFolderName="Properties">
<ProjectItem ReplaceParameters="true" TargetFileName="AssemblyInfo.cs">AssemblyInfo.cs</ProjectItem>
</Folder>
<Folder Name="Views" TargetFolderName="Views">
<Folder Name="Home" TargetFolderName="Home">
<ProjectItem ReplaceParameters="true" TargetFileName="Index.cshtml">Index.cshtml</ProjectItem>
</Folder>
<Folder Name="Shared" TargetFolderName="Shared">
<ProjectItem ReplaceParameters="true" TargetFileName="_Layout.cshtml">_Layout.cshtml</ProjectItem>
</Folder>
<ProjectItem ReplaceParameters="true" TargetFileName="web.config">web.config</ProjectItem>
</Folder>
<ProjectItem ReplaceParameters="true" TargetFileName="Web.config">Web.config</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="Web.Debug.config">Web.Debug.config</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="Web.Release.config">Web.Release.config</ProjectItem>
</Project>
</TemplateContent>
</VSTemplate>
That takes care of the .vstemplate file. The last step we need to take is to edit the _preprocess.xml file. All we need to change in it is the TemplateInfo elements’ Path attribute – this is used to specify where the template will show up in Visual Studio. We also need to add a key to replace the project template with a safe project name. The xml for the _preprocess.xml file looks like:
_preprocess.xml
<?xml version="1.0" encoding="utf-8" ?>
<Preprocess>
<TemplateInfo Path="CSharpMythical Man Moth"/>
<Replacements Include="*.*" Exclude="*.vstemplate;*.csproj;*.fsproj;*.vbproj;*.jpg;*.png;*.ico;_preprocess.xml">
<add key="FoundationProject" value="$safeprojectname$"/>
</Replacements>
</Preprocess>
Build and run the project. This will start an experimental instance of Visual Studio. Select File > New Project. You should see a new entry under Visual C# entitled Mythical Man Moth and in this section, you should see our project template:

When you create the project. It should create a new ASP.Net MVC project with all the necessary assets to build a Zurb Foundation website.

One thing you’ll notice is that you’ll have to restore the Nuget packages for the project in order for it to build successfully. I’ll explain how you can include Nuget packages in your Visual Studio extensions in a future post. I’ll also show you how you can add your own wizard UI’s and how to create item templates.
That’s it for this post. Thank you for reading. Until next time, keep coding!