Creating custom project template with wizard for Visual Studio

Introduction

If you are a experienced .Net developer, you might have already created or used custom project template in Visual Studio. In new versions of Visual Studio, Microsoft has included common files like jQuery, CSS, standard Master page etc. in the default web site template which was not there in old Visual Studio versions.

I always require jQuery file, standard CSS file of client, some common logo images to be added in my new projects. Also, whenever I creat a new project, I require to modify the connection string by going to web.config file. There are also some other common setting which I repetatively do in web.config.

Visual Studio provides some easy way of creating a cusomt project template so that, such a common items and code can be included in the new project template.

In this short article, I will explain about

  • Creating project template
  • Creating DLL for new project wizard dialogue
  • Incorporating new wizard in project template to accept additional input from user
  • Using project template to create new website

Article Body

Note that, I am using web site project as a example in complete article. However, this is applicable for web application or any other project (including console application, WinForm application etc.)

Lets first start by creating simple project template which will contain common files that we require in most of our projects. You might be aware that, Visual Studio provide a option of exporting existing open project as temaplate. You can simply open a web site project and then go to File -> Export Temaplate and then follow the wizard stepas this will make current project as a template which can be used as a base while opening new project next time.

However, to have more control over templated items and to use separate wizard dialouge etc. we can follow steps given below (Which is the focus of the article)

Creating simple project template first

Suppose, I want that jQuery file be added by default when I creat new project (This is already there in Visual Studio 2010 but not in VS 2005) also, there is a standard CSS file and a image file which should be included. Also, there is public function class file which I want to use across all my projects.

Lets first creat new web site project and add all these files into this project.

Now, add new XML file in the root directory of project and name it as ProjectTemplate.vstemplate. This is the file which will contains information required to create new project in VS. The content of .vsTemplate file are diaplayed below (note that you could name the file as per your choice)

<VSTemplate Version="2.0.0" Type="Project"
    xmlns="http://schemas.microsoft.com/developer/vstemplate/2005">
  <TemplateData>
    <Name>Blue Lemon Default Project Template</Name>
    <Description>A web site project template by Kedar</Description>
    <Icon>lemon.ico</Icon>
    <ProjectType>Web</ProjectType>
    <ProjectSubType>CSharp</ProjectSubType>
    <DefaultName>WebSite</DefaultName>
  </TemplateData>
  <TemplateContent>
    <Project File="WebApplication.webproj">
      <Folder Name="App_Code"  TargetFolderName="App_Code">
        <ProjectItem ReplaceParameters="true">pubClass.cs</ProjectItem>
      </Folder>
      <Folder Name="Scripts"  TargetFolderName="Scripts">
        <ProjectItem>jquery-1.4.1.js</ProjectItem>
        <ProjectItem>jquery-1.4.1.min.js</ProjectItem>
        <ProjectItem>MyJS.js</ProjectItem>
      </Folder>
      <Folder Name="Styles"  TargetFolderName="Styles">
        <ProjectItem>StandardTheme.css</ProjectItem>        
      </Folder>
      <ProjectItem>lemon.ico</ProjectItem>
      <ProjectItem OpenInEditor="true">Default.aspx</ProjectItem>
      <ProjectItem ReplaceParameters="true">Default.aspx.cs</ProjectItem>
      <ProjectItem ReplaceParameters="true">web.config</ProjectItem>
    </Project>
  </TemplateContent>
</VSTemplate>

The purpose of various tags inside <TemaplateData> in above XML format is evident from their name. You can change these values as per your choice (like ProjectType could be either CSharp/VisualBasic/JSharp/Web so that project template can be categorized into appropriate type).

Inside <TemplateData> tag, I have included <Icon> tag and specified name of .ico file. The Icon tag information is used to display picture of project template while creating new project. I strongly advice to read this to know more about template data.

In <TemplateContent> tag, we need to mention details of all files which we wish to include in the template. Creat structre of all necessary file by using <Folder… > to mention folder name (like App_Code) and use <ProjectItem …> tag to give file details. As name suggest by setting OpenInEditor=”true” in ProjectItem tag, the respective file can be set to be opened by default when you start a new project  by selecting this template. There is another attribute of ProjectItem as ReplaceParameters. This can be set to true so that dyamic paramters can be added into the file and used by template when creating new project.

To see its use, open pubClass.cs file from App_Code and change its namespace value as $safeprojectname$. The content of class file looks as

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace $safeprojectname$
{
/// <summary>
/// Summary description for Class1
/// </summary>

    public class PubClass
    {
        public void ExecuteQuery()
        {

        }
    }

}

The parameter $safeprojectname$ in above code has certain meaning in Visual Studio project template. VS provides name entered by user in New project dialogue in this parameter. By setting ReplaceParameter to True for pubClass.cs file in XML file above, we have intimated VS to replace $safeprojectname$ in pubClass.cs with new project name enterd by user.

In above XML format, there is a tag as <Project File=”WebApplication.webproj”>. Although, Web site project does not have any solution or project file, it is required for interanl purpose. Hence, go to folder location where you have defined this project and create new blank file and name it as WebApplication.webproj.

After refreshing project in Visual Studio, below is list of files available.

If you want just to create simple projetc template without any additional dialogue and just default set of files. Then you can jump to third section (However, I would suggest to read on next section)

Creating DLL for new Project wizard dialogue

Until this it is fine. But what if I want that when I create a new project using custom template it should ask me for connectionstring setting I want to add in my web.config file? so that I dont have open web.config file and add connection string value again after project is started.

Project template wizard could come handy in such situations. However, it is not straightforward as creating project template. To add wizard form in project template, we have to create a separate class library project and follow below steps.

Create new class library project and add a windows form in it with required wizard design

Right click on project in solution explorer and select windows form. name it as wizardForm.cs and create form design (in this case, I want to let use to enter connection string and some other custom message)

In the wizardForm.cs c# code, create public properties to return value of form fields. The complete code is

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace CustomOptions
{
    public partial class wizardForm : Form
    {
        public string strCustomMessage;
        public string strConnectionstring;
        public wizardForm()
        {
            InitializeComponent();
        }

        public string get_CustomMessage()
        {
            return strCustomMessage;
        }

        public string get_ConnectionString()
        {
            return strConnectionstring;
        }

        private void btnAdd_Click(object sender, EventArgs e)
        {
            strCustomMessage = txtParameter.Text;
            strConnectionstring = txtConnectionstring.Text;           
            this.Dispose();
        }
    }
}

Update class file to create wizard template assembly

Now is the time to update class file of to create project template assembly. Before that, it is required that we add reference to following assemblies in the project

Right click on project -> select Add reference. In .Net tab select Microsoft.VisualStudio.TemplateWizardInterface, System.Windows.Forms and EnvDTE. In the class.cs file (or you might have different name to this file) add using statement to these namespace (in case of vb.net, it is import).

We required to create a class which inherits form IWizard interface. IWizard has many other functions out of which we are going to provide implementation for RunStarted and RunFinished.

using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TemplateWizard;
using System.Windows.Forms;
using EnvDTE;

namespace CustomOptions
{

    public class WizardClass : IWizard
    {
        private wizardForm wizardFrm;
        private string customMessage;
        private string strConnectionstring;

        public void BeforeOpeningFile(ProjectItem projectItem)
        {
        }

        public void ProjectFinishedGenerating(Project project)
        {
        }

        public void ProjectItemFinishedGenerating(ProjectItem projectItem)
        {
        }

        public void RunFinished()
        {
            MessageBox.Show("The custom options has been added. Creating new project with selected template and parameters");
        }

        public void RunStarted(object automationObject, Dictionary<string, string> replacementsDictionary, WizardRunKind runKind, object[] customParams)
        {
            try
            {
                //Call win form created in the project to accept user input
                wizardFrm = new wizardForm();
                wizardFrm.ShowDialog();
                //call property from wizardForm to read user input values
                customMessage = wizardFrm.get_CustomMessage();
                strConnectionstring = wizardFrm.get_ConnectionString();
                // Add custom parameters.
                replacementsDictionary.Add("$custommessage$", customMessage);
                replacementsDictionary.Add("$connectionstring$", strConnectionstring);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        public bool ShouldAddProjectItem(string filePath)
        {
            return true;
        }
    }
}

Note carefully that, all we are doing in RunStarted method is displaying wizard dialogue, reading values entered by user in wizard form and add it in dictionary variable. We are also adding a string enclosed in $. This works as a key which we would use later in project template to read user inputted value and replace in template pages.

Sign assembly and add in GAC

We have now completed creating wizard form. To use it in project template, the assembly needs to signed with strong name and be added in GAC. To sign assembly, right click project go to Properties in project properties page go to Signing tab -> check “sign the assembly” checkbox. In “Choose string name key file”, select New. Then in new dialogue, enter Key file and password/s the key file (.pfx) would be generated in root of project.

This assembly now needs to be added in GAC (global assembly cache) you might already know how to do it or read this.

Incorporating new wizard in project template to accept additional input from user

We now have a custom project template and a template wizard assembly. Now go back to our original project template (step 1 above). In the .vsTemplate XML file, we have to add reference to the assembly we just created. To do that, add following tags after closing </TemplateContent> tag

<WizardExtension>
    <Assembly>
      wizardTemplate, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0abc167b5bd11206
    </Assembly>
    <FullClassName>CustomOptions.WizardClass</FullClassName>
  </WizardExtension>

Note that, we need assembly information for this. To get assembly information of just added assembly, go to Visual studio command prompt and type

> gacutil -l <wizardProjectNameSpace>

this will give us the assembly information string which we can copy and paste into <WiardExtension> tag above. Also note that, FullClassName tag should indicate namespace.classname of wizard project.

If you see complete XML format of .vsTemplate file, we had set ReplaceParameter to true for web.config as well as default.aspx. That is because, the we are going to replace values in these files with string entered by user in wizard form.

Go to web.config file of project template add replace connectionstring tag as

<connectionStrings>
    <add name="ApplicationServices"
         connectionString="$connectionstring$"
         providerName="System.Data.SqlClient" />
  </connectionStrings>

The $connectionstring$ indicate that value of $connectionstring$ parameter should be replace here. One final thing we are left with is to package the template project. To do this, go to folder location where template  project is saved. in the root directory, select all files -> right click -> send to -> Compressed (zipped) Folder.

We now need to add this zip file into default template location of visual studio. Mostly (unless you have changed) VS template stored at

\My Documents\Visual Studio 2010\Templates\ProjectTemplates\<Language>\

or

\My Documents\Visual Studio 2010\Templates\ProjectTemplates\Visual Web Developer

Read this to know how can you find default location of project template on your machine. Once the default location is identified, copy and paste the zip file here and that’s it!

Using project template to create new website

To test the project template with wizard, open new Visual studio instance and go to File -> New web site. The new project name can be seen here

Select this new project template and click OK. A dialgue will appear as this. Add values in the textboxes

Then click on Add button. The project will start with all default files selected by us as part of template. Go to web.config file now. whoo! instead of $connectionstring$ you can now see value entered by us in project wizard dialogue.

Conclusion

Diffrent functionality of Visual Studio can be extended very easily. By creating custom wizard in project template we can do lot of many other things to speed up development process. With NuGet, it is more easier to use any existing project templates.

If you know of any NuGet package which takes care of creating project template wizard then please update us.

Thanks for visiting my site. Your comments are welcome 🙂