Sunday, November 23, 2008

Write Visual Studio 2008 multi-file item templates

When you add a new item to an existing project in Visual Studio.NET, you’re actually using an item template that would be either an out-of-box template or a custom template.  I will explain how to put together a custom item template in this blog and also how to package it up and have other developers install it in their development environments.

An example of a multi-file item template is a Web Form when working with a Web Application.  When you create a web form 3 files are generated: webform.aspx, webform.aspx.cs and webform.aspx.designer.cs.  Also, the same principles apply for to a project template in Visual Studio however a project template is not discussed in this blog post.

There are basically 2 zip file to be created and one is going to be embedded inside the other.

  1. The first zip file, contains a .vstemplate, .ico and a few other files that are used to auto-generate the multi-part item.  This zip file will be embedded into the the second zip file however as you will see, the second zip file will have an extension of .vsi.
  2. The second zip file (which once zipped, we will change its extension to .vsi instead) contains the first zip file and a .vscontent file.

Important note: In this article I will discuss the manual process with which you can put together a multi-file item template.  If you were creating a single-file item or project template you could have used the “Export Template Wizard” in Visual Studio 2008 under the File menu.  You can find detailed how-to articles on using the Export Template Wizard on MSDN.

The Content file - First ZIP file

ICON file

The ICON file is used to show a distinct icon in the “Add New Item” windows in Visual Studio.  An example of an icon that was used on the “Design Pattern Code Generator” project on Codeplex is shown below:

iconfile

The .VSTEMPLATE (or the Visual Studio Template) file

This is a XML file containing the metadata about the project files.  The same type of file is used for both an item template and project template.  For the most part this metadata file consists of two main and required elements.

a) TemplateData: Contains data about project name, description, type (e.g. C# or Visual Basic), the sub-type that the item template is to appear under and the icon file.

  <TemplateData>
<
DefaultName>YourDataProviderName</DefaultName>
<
Name>Provider Model</Name>
<
Description>Provider Model - Please provide a name without an extension</Description>
<
ProjectType>CSharp</ProjectType>
<
ProjectSubType>Code</ProjectSubType>
<
SortOrder>1</SortOrder>
<
Icon>ProviderModel.ico</Icon>
<
RequiredFrameworkVersion>3.5</RequiredFrameworkVersion>
</
TemplateData>

b) TemplateContent: The sub-elements of this element describe the structure of the template and also allows for declaring custom parameters that may be passed into the template files.  The ProjectItem sub-elements must match one-to-one with the multiple files that are included in the generation of the template.

Note that the first of the ProjectItem sub-elements opens when a new item of your custom item template is created.  For example, consider the Web Form item template.  When you create an item of this type, the .aspx file opens in the IDE first when the item is created first.

  <TemplateContent>
<
References> … </References>
<
CustomParameters>
<
CustomParameter Name="$Suffix$" Value="DataProvider"/>
</
CustomParameters>
<
ProjectItem
SubType="Code"
TargetFileName="To-Do-$fileinputname$.txt"
ReplaceParameters="true">
To-Do-PM.txt
</ProjectItem>
<
ProjectItem
SubType="Code"
TargetFileName="FirstDataProvider.cs"
ReplaceParameters="true">
FirstDataProvider.cs
</ProjectItem>
<
ProjectItem
SubType="Code"
TargetFileName="$fileinputname$$Suffix$.cs"
ReplaceParameters="true">
DataProvider.cs
</ProjectItem>
<
ProjectItem
SubType="Code"
TargetFileName="$fileinputname$$Suffix$Collection.cs"
ReplaceParameters="true">
DataProviderCollection.cs
</ProjectItem>
<
ProjectItem
SubType="Code"
TargetFileName="$fileinputname$$Suffix$Manager.cs"
ReplaceParameters="true">
DataProviderManager.cs
</ProjectItem>
<
ProjectItem
SubType="Code"
TargetFileName="$fileinputname$$Suffix$Configuration.cs"
ReplaceParameters="true">
DataProviderConfiguration.cs
</ProjectItem>
<
ProjectItem
SubType="Code"
TargetFileName="ConfigSection.config"
ReplaceParameters="true">
Configuration.config
</ProjectItem>
</
TemplateContent>
Project Items

These are files that make the item.  In this article’s example, there are multiple items as seen under the TemplateContent element explained previously.

Each of these project items have place holders  in the format of $[a-z-A-Z0-9]$.  The following table outlines the most used and a brief description of each of valid place holders that could be used.

Tag name Description
$itemname$ Target file name as designated in the .vstemplate file
$safeitemname$ Same as $itemname$ with all unsafe characters replaced
$fileinputname$ The file name provided by user without it's extension
$fileinputextension$ Extension of $fileinputname$
$rootnamespace$ The namespace of your item at level of class.
$clrversion$ Installed CLR version
$machinename$ Computer name
$registeredorganization$ The registered company name of the Windows OS. Registry key value for HKLM\Software\Microsoft\Windows NT\CurrentVersion\RegisteredOrganization
$time$ Current datetime in DD/MM/YYYY HH:MM:SS format
$userdomain$ Current user domain
$username$ Current logged-in user

In the example below a C# class file is expressed as a project item using a combination of the above tags.

namespace $rootnamespace$
{
/// <summary>
///
A singleton class that manages the providers collection
/// </summary>
public class $safeitemname$
{
static $fileinputname$DataProviderManager()
{
Initialize();
}

private static $fileinputname$DataProvider _default;
/// <summary>
///
Returns the default configured data provider
/// </summary>
public static $fileinputname$DataProvider Default
{
get { return _default; }
}

private static $fileinputname$DataProviderCollection _providerCollection;
/// <summary>
///
Returns the provider collection
/// </summary>
public static $fileinputname$DataProviderCollection Providers
{
get { return _providerCollection; }
}

private static ProviderSettingsCollection _providerSettings;
public static ProviderSettingsCollection ProviderSettings
{
get { return _providerSettings; }
}

}
}
Packaging the first ZIP file

The Icon, Visual Studio Template and all of the project item files (in the same folder structure as described in the vstemplate file) are packaged and compressed using the ZIP archive format.

firstzip

The VSTemplate - The Second ZIP file

This file consists of the first ZIP file (as explained above) and a Visual Studio Content Installer (.vscontent) file.  The packaging of this is pretty simple.  Create an archive file that includes the two files and then you must change its extension from ZIP to VSI.  Below I will explain the Installer file.

The Visual Studio Content Installer

This file contains metadata about the project itself.  The elements and sub-elements describe where the location of the Content file, name and description of the project and a few attributes.  The attributes are project type, sub-type as well as the template type, i.e. item or project template.

<VSContent xmlns="http://schemas.microsoft.com/developer/vscontent/2005">
<
Content>
<
FileName>ProviderModelItemTemplate.zip</FileName>
<
DisplayName>Provider Model Template</DisplayName>
<
Description>Generates provider model related classes and configuration files</Description>
<
FileContentType>VSTemplate</FileContentType>
<
ContentVersion>2.0</ContentVersion>
<
Attributes>
<
Attribute name="ProjectType" value="Visual C#"/>
<
Attribute name="ProjectSubType" value="Code"/>
<
Attribute name="TemplateType" value="Item"/>
</
Attributes>
</
Content>
</
VSContent>

References

1 comments:

Anonymous said...

Excellent, thank you very much!