Creating Visual Studio project templates

Reason

Creating the basic structure of a Visual Studio project (inserting copyright info, adding commonly used assembly references, setting the default namespace/adding file system folders etc.) quickly becomes tiresome — this is particularly true when working as a web consultant, creating solutions for a wide range of customers.
Using project templates which provide the basic structure of e.g. a component can save a lot of time in the long run, as most of the trivial configuration tasks can be handled automatically. Project templates also offer an excellent opportunity to provide your colleagues with implementation examples and boilerplate code which follow company and industry best practices.

Code

A project template consists of:

  • A manifest of the files and folders which make up the template (a *.vstemplate file)
  • A project file (e.g. *.csproj for a C# project)
  • Other files that should to be part of the template (e.g. AssemblyInfo.cs)

The following steps outline the way I usually create project templates:

  1. Create a project resembling the intended structure and content of the template.
  2. Copy all the files in the project folder to a suitable subfolder in the Visual Studio project template root.
  3. Add a basic vstemplate file to the template folder.
  4. Add custom parameters to the vstemplate file and use them in the various “file blueprints” of the template.
  5. Use the template to create a new project. Check to make sure all custom parameters and files are inserted as intended. Repeat steps 4 & 5 until satisfied with the result.
  6. Make the template available to colleagues by e.g. deploying it to a network share.

Steps 1 – 4 are described in more detail below.

1. Create template structure

Simply create a project, add some files to it, set root namespace and similar assembly information, add company and copyright info etc.

2. Copy template structure to project template folder

The project template root is configured in Visual Studio via “Tools → Options… → Projects and Solutions → User project templates location”.

Template root folder configuration

Put the files from step 1 into the subfolder matching the project language beneath the project template root, e.g. “[project template root]/Visual C#/[…]” for a C# project.
At this point the contents of e.g. “[project template root]/Visual C#/Reason→Code→Example/Component” simply consist of the project file (Component.csproj) and two class files (“/Properties/AssemblyInfo.cs” and “Constants.cs”).

Component template files

3. Add a vstemplate file

Without a vstemplate file, Visual Studio will not recognize the files from step 2 as a template, and will hence not show it as an option in the “Add new project”-dialog. For an in depth description of the vstemplate format, see MSDN.

Component vstemplate file

An example of a vstemplate file (“template manifest”) is shown below, intended to be used in componentized solutions. The manifest makes it easy for me to tailor company specific information to clients, thus not having to modify other files in the project template. When giving lectures in Sitecore component architecture I usually hand out a project template based on the manifest shown below to developers at the start of the course.

<VSTemplate Version="3.0.0" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005" Type="Project">
  <TemplateData>
    <Name>Component</Name>
    <Description>Creates the basic file structure for a standard component.</Description>
    <ProjectType>CSharp</ProjectType>
    <ProjectSubType></ProjectSubType>
    <SortOrder>10</SortOrder>
    <CreateNewFolder>true</CreateNewFolder>
    <DefaultName>Component</DefaultName>
    <ProvideDefaultName>true</ProvideDefaultName>
    <LocationField>Enabled</LocationField>
    <EnableLocationBrowseButton>true</EnableLocationBrowseButton>
    <Icon>Reason→Code→Example.ico</Icon>
  </TemplateData>
  <TemplateContent>
    <!-- TargetFileName provided since Microsoft might some day decide to fix project renaming bug detailed here:
    http://social.msdn.microsoft.com/Forums/en-US/vsx/thread/ff5e300b-41c1-4d19-bb7f-68dc135f315e -->
    <Project File="Component.csproj" TargetFileName="$fileinputname$.csproj" ReplaceParameters="true">
      <ProjectItem TargetFileName="Constants.cs" ReplaceParameters="true">Constants.cs</ProjectItem>
      <!-- Empty folders are created automatically upon project creation,
      hence don't have to exist "on disk" in the project template -->
      <Folder Name="Infrastructure" TargetFolderName="Infrastructure" />
      <Folder Name="Model" TargetFolderName="Model" />
      <Folder Name="Repositories" TargetFolderName="Model/Repositories" />
      <Folder Name="Factories" TargetFolderName="Model/Factories" />
      <Folder Name="Presentation" TargetFolderName="Presentation" />
      <Folder Name="Properties" TargetFolderName="Properties">
        <ProjectItem ReplaceParameters="true" TargetFileName="AssemblyInfo.cs">AssemblyInfo.cs</ProjectItem>
      </Folder>
    </Project>
    <!-- Custom parameters to be used when replacing values in created files -->
    <CustomParameters>
      <CustomParameter Name="$company$" Value="Reason→Code→Example"/>
      <CustomParameter Name="$company-url$" Value="http://reasoncodeexample.com"/>
      <CustomParameter Name="$company-founding-year$" Value="2012"/>
      <CustomParameter Name="$namespace-prefix$" Value="ReasonCodeExample."/>
    </CustomParameters>
  </TemplateContent>
</VSTemplate>

4. Add custom parameters to template files

In the vstemplate shown in step 3, the following custom parameters are defined:

  • $company$
  • $company-url$
  • $company-founding-year$
  • $namespace-prefix$

In addition to custom parameters, the following standard parameters are available for use (see MSDN for further details). Only some of these are of interest when working with templates, others are aimed more towards project and solution wizards:

  • $guid1$, $guid2$, $guid3$, $guid4$, $guid5$
  • $time$
  • $year$
  • $username$
  • $userdomain$
  • $machinename$
  • $clrversion$
  • $registeredorganization$
  • $runsilent$
  • $targetframeworkversion$
  • $projectname$
  • $safeprojectname$
  • $installpath$
  • $exclusiveproject$
  • $destinationdirectory$

To use parameters in a file template, open it in a text editor, insert the parameter and make sure the ReplaceParameters-attribute is set to “true” for the appropriate node in the vstemplate file (e.g. “<Project File=”Component.csproj” TargetFileName=”$fileinputname$.csproj” ReplaceParameters=”true”>”).

Excerpts of how these parameters are used in a csproj-file are shown below:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProductVersion></ProductVersion>
    <SchemaVersion>2.0</SchemaVersion>
    <!-- Use standard parameter to insert project GUID -->
    <ProjectGuid>$guid1$</ProjectGuid>
    <ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
    <OutputType>Library</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
    <!-- Use custom and standard parameters to set the default namespace and assembly name -->
    <RootNamespace>$namespace-prefix$$safeprojectname$</RootNamespace>
    <AssemblyName>$safeprojectname$</AssemblyName>
    <!-- Notice a "v" is required in front of the target framework parameter -->
    <TargetFrameworkVersion>v$targetframeworkversion$</TargetFrameworkVersion>
  </PropertyGroup>
[...]
  <ItemGroup>
    <!-- Add often used libraries to the template -->
    <Reference Include="Sitecore.Kernel">
      <HintPath>..\..\bin\Sitecore.Kernel.dll</HintPath>
    </Reference>
    <Reference Include="System" />
    <Reference Include="System.Xml.Linq" />
    <Reference Include="System.Web" />
    <Reference Include="System.Xml" />
  </ItemGroup>
[...]
  <PropertyGroup>
    <!-- Set up build events as necessary -->
    <PostBuildEvent>COPY "$(TargetDir)$(TargetName).*" "$(SolutionDir)www\bin"</PostBuildEvent>
  </PropertyGroup>
[...]
</Project>

Using parameters in other file types follows the same pattern.

Example

The example shown below is a template intended for a “single project 3-tier Sitecore CMS solution”. The vstemplate file is set up as follows:

<VSTemplate Version="3.0.0" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005" Type="Project">
  <TemplateData>
    <Name>Sitecore Web Project</Name>
    <Description>Creates a web project suitable for a standard Sitecore solution.</Description>
    <ProjectType>CSharp</ProjectType>
    <ProjectSubType></ProjectSubType>
    <SortOrder>10</SortOrder>
    <CreateNewFolder>true</CreateNewFolder>
    <DefaultName>Use company naming convention</DefaultName>
    <ProvideDefaultName>true</ProvideDefaultName>
    <LocationField>Enabled</LocationField>
    <EnableLocationBrowseButton>true</EnableLocationBrowseButton>
    <Icon>Sitecore.ico</Icon>
  </TemplateData>
  <TemplateContent>
    <CustomParameters>
      <CustomParameter Name="$company$" Value="Reason→Code→Example"/>
      <CustomParameter Name="$company-url$" Value="https://reasoncodeexample.com/"/>
      <CustomParameter Name="$company-founding-year$" Value="2011"/>
      <CustomParameter Name="$assembly-prefix$" Value="ReasonCodeExample."/>
      <CustomParameter Name="$namespace-prefix$" Value="ReasonCodeExample."/>
    </CustomParameters>
    <Project File="SitecoreWebProject.csproj" ReplaceParameters="true">
      <Folder Name="Properties" TargetFolderName="Properties">
        <ProjectItem ReplaceParameters="true" TargetFileName="AssemblyInfo.cs">AssemblyInfo.cs</ProjectItem>
      </Folder>
      <Folder Name="BL\Constants" TargetFolderName="BL\Constants">
        <ProjectItem ReplaceParameters="true" TargetFileName="FieldIDs.cs">FieldIDs.cs</ProjectItem>
        <ProjectItem ReplaceParameters="true" TargetFileName="TemplateIDs.cs">TemplateIDs.cs</ProjectItem>
      </Folder>
    </Project>
  </TemplateContent>
</VSTemplate>

Selecting a custom project template

After creating the project, the root namespace, framework etc. have been set to the values selected in the wizard.

Sitecore solution project settings from custom project template

The layers “DAL”, “BL” and “UI” have been created as folders. As mentioned earlier, this is a good way of conveying company best practices to colleagues, helping to enforce a uniform structure recognizable across all solutions your company is maintaining.

Sitecore solution from custom project template

Shown below is an example of a file template, in this case AssemblyInfo.cs:

AssemblyInfo.cs without replaced values

As can be seen below, the standard and custom parameters are replaced with values from the vstemplate file as well as values provided by the “Add new project” wizard:

AssemblyInfo.cs with replaced values

8 thoughts on “Creating Visual Studio project templates

  1. Is it posiible to create multiple project template? I am looking for a template which will define a Three tire architecture template which will have different projects such as BLL, DAL, Views etc.

    • To my knowledge there’s still no simple way of doing this, simple in this case meaning using only template files. If you want to create multiple projects in one go you’ll have to implement a “custom wizard” (see http://msdn.microsoft.com/en-us/library/7k3w6w59.aspx). I’ve created a solution wizard before using this guide – I’ll write a post about it if it’s of interest 🙂
      I’d suggest doing the following:

      1. Create a project template for each of the project types you’d like to include in the solution, and make these work.
      2. Once the templates work flawlessly and your colleagues start complaining about having to create 3+ projects every time they create a new solution, have a go at creating a custom wizard.

      Creating a wizard isn’t rocket science, but you’ll need the project templates anyway so creating these first will get you started and provide something useful to you/your company immediately.

  2. Hi Uli,

    do you have any clue where $targetframeworkversion$ is set and how to change it?

    Thanks

    • Hi Mario,

      The $targetframeworkversion$ parameter is set by the “New project”-dialog. So it’s the users choice at the time of project creation, and is set to the value selected in the “target framework” dropdown list in the “New project”-wizard.
      It’s the same way e.g. the $projectname$ parameter is set to the name the user types into the “Name” text box in the wizard.

  3. Uli you rock!
    I have spent several hours searching for this answer and it was just under my nose! Seems so obvious but it is not. Pity that MSDN doesn’t say it anywhere.

    Thanks

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s