I love techniques that help shave time off of software development and the ability to create templates in Visual Studio is one of those features that doesn’t get the use it deserves. In this post, I’ll describe how to create a template, some things to look out for when managing your template and a few tips on how to optimize working with templates.
Creating a Template
Creating a template is easy. In Visual Studio, simply select Export Template and follow the wizard.
That’s great, but when you’re done and you create a new project based on this template, you realize really soon that the template you’ve created is kind of static, leaving you with the job of changing the filenames as well as the names of key objects in your project.
Luckily, there’s a way to work around this limitation. The Visual Studio template architecture is designed to allow developers to create fairly extensible template solutions. And one feature that you’ll find really helpful is the ability to use tokens in your templates, the most useful of which is the $safeprojectname$ token.
The $safeprojectname$ token is replaced during project creation by the name of the project entered by the user, and you can use this token anywhere in your code, including in the files names. I’m assuming in this post that you’re creating a project template, since this is the most common type of template developers create. You can also create an item template. The steps for creating an item template are similar. The MSDN articles for both are available here (VS2005) and here (VS2008).
Some other tokens that you can use are:
- clrversion - Current version of the common language runtime (CLR).
- GUID [1-10] - A GUID used to replace the project GUID in a project file. You can specify up to 10 unique GUIDs (for example, guid1).
- itemname - The name provided by the user in the Add New Item dialog box.
- machinename - The current computer name (for example, Computer01).
- projectname - The name provided by the user in the New Project dialog box.
- registeredorganization - The registry key value from HKLM\Software\Microsoft\Windows NT\CurrentVersion\RegisteredOrganization.
- rootnamespace - The root namespace of the current project. This parameter is used to replace the namespace in an item being added to a project.
- safeitemname - The name provided by the user in the Add New Item dialog box, with all unsafe characters and spaces removed.
- safeprojectname - The name provided by the user in the New Project dialog box, with all unsafe characters and spaces removed.
- time - The current time in the format DD/MM/YYYY 00:00:00.
- userdomain - The current user domain.
- username - The current user name.
- year - The current year in the format YYYY.
To use the token, simply surround it with the $ as shown above. See the MSDN entry for more information.
We’ve assumed so far that we’re creating a project template, but it’s just as easy to create an item template.
Troubleshooting
As much time as templates promise to save, I’s kind of funny when I think of how much time I’ve spent trying to troubleshoot issues related to templates.
One nasty issue that took me hours to track down relates to the following error message you may receive when attempting to create a new project based on a template.
---------------------------
Microsoft Visual Studio
---------------------------
Unable to copy the file 'Client_ModDev1_Edit.ascx.resx' from the project template to the project. Cannot find file "C:\Documents and Settings\don.lastname\Local Settings\Temp\ycan5tri.msp\Temp\App_LocalResources\Client_ModDev1_Edit.ascx.resx".
---------------------------
OK
---------------------------
I went round and round with Visual Studio before I finally figured out that this issue can occur when the project name includes spaces or starts with a number. So, note to self, don’t create projects in Visual Studio based on a template that use a space.
Another issue you may run into is the path to the files you save in your zip files. The critical part is to make sure that the vstemplate file is available at the root of your zip file. Check the Path column to make sure you haven’t inadvertently zipped your files too far up the folder hierarchy. Here’s what the path column looks like at the top of one of my template zip files:
A common mistake is to right click the folder which contains your project template and zip the entire folder, especially if you’ve extracted your project files in order to add template tokens.
Finally, one last common mistake is to use the template token to change filenames, but not update the project file, or vice versa. If you use one of the template tokens to change filenames, you’ll need to make sure to use the tokenized version of that filename everywhere it exists. So, if you’ve created a file named $safeprojectname$_orders.aspx, you’ll want to make sure that the references to this filename in code and in the csproj or vbproj files are all identical.
No doubt there are some I’ve missed. Hopefully, though, not the issue that’s holding you back right now from progress. Please leave a comment if you run into an issue that I haven’t included here.
Optimizing Template Development and Maintenance
Another issue I’ve had is general management of the template files after I’ve modified the files to include the tokens. The process you go through to make changes to your template can be time consuming, especially when you have to test each change in Visual Studio. My workaround for this was to work with my project template files in a directory and then manage the creation of the zip file along with the vsi file used to easily install my template using a batch file, the WinZip command line tool (which comes with a licensed copy of WinZip) and an entry in the PATH system variable to make running the WinZip command easier.
Here’s the set of files I use along with the directory which contains the expanded version of my template:
The directory on the bottom contains the expanded view of the project template’s files, which I created initially as follows:
- Created the project in Visual Studio and used the Export Template feature shown above.
- Changed the filenames to include the $safeprojectname$ token and then opened the projects file (.csproj in my case) and replaced the project name (which I had created to be as unique as possible) with the $safeprojectname$ token.
- At this point, my project file was consistent with the files included in the project, so I opened the project in Visual Studio and did a quick find and replace on the project name as I did in the last step.
Because I wanted to make it as easy as possible for staff and/or customers to use the template, I took the time to create a vsi file, which is the installer file for Visual Studio. It’s actually really simple to create, since a vsi file is nothing more than a zip file renamed with the vsi extension. This zip file needs to contain an XML manifest file with the same name used for the vsi file. In my case, I named my vsi file MemberCrossing.vsi, so I named my vscontent file MemberCrossing.vscontent. Here are the contents of the vscontent file I used:
<VSContent xmlns="http://schemas.microsoft.com/developer/vscontent/2005">
<Content>
<FileName>MC_DNN_MVP_Template.zip</FileName>
<DisplayName>Member Crossing Compiled Module (C#)</DisplayName>
<Description>Creates a Member Crossing Module</Description>
<FileContentType>VSTemplate</FileContentType>
<ContentVersion>1.0</ContentVersion>
<Attributes>
<Attribute name="ProjectType" value="Visual C#"/>
<Attribute name="ProjectSubType" value="Web"/>
<Attribute name="TemplateType" value="Project"/>
</Attributes>
</Content>
</VSContent>
If you want to learn more about the structure of the vscontent file and how you might use it to create a template installer for other types of projects, here’s a great place to start.
Once I had my vscontent file created, I was ready to write a little batch file which has saved me a ton of time as I have gone back to the template folder and made changes to my template. If you’re like me, you’ll have a few iterations before things work perfectly, and this is where the batch file really begins to save you time. Here’s the batch file I use:
cd MC_DNN_MVP_Template
wzzip -p -r -a MC_DNN_MVP_Template.zip *.* -x_svn
move /Y MC_DNN_MVP_Template.zip ../MC_DNN_MVP_Template.zip
cd ..
wzzip -a MemberCrossing.vsi MC_DNN_MVP_Template.zip
copy MC_DNN_MVP_Template.zip "%UserProfile%\My Documents\Visual Studio 2005\Templates\ProjectTemplates\Visual C#\Web"
copy MC_DNN_MVP_Template.zip "%UserProfile%\My Documents\Visual Studio 2008\Templates\ProjectTemplates\Visual C#\Web"
The call to wzzip works without a path because I’ve registered the path to the WinZip executable in my system PATH variable, and of course, you may be using your own command line tool to zip your files. The last two lines copy to the template directory I use for both VS 2005 and VS 2008.
Hey, I hope this helps you save some time!