I finally have the setup working. It took me many days of experimenting and patching together different MSDN articles and blogs to figure this out.
Combining Multi project template (with root template) and VSIX
The end result is
- Visual Studio 2012 VSIX project, which holds a packages folder that has all the nuget dependencies.
- A Zip file with the root/master template which links the multiple projects together that are also in the zip file in their corresponding folders.
- A built vsix installer which will install a single project template that has sub projects.
- This will allow you to maintain a template from a project that continues to grow, with very little effort, using the File-Export Template feature.
- Uses auto generated and customizable parameters to rename your template namespaces and files to match your new project name.
When creating a project with this template, it automatically creates multiple sub-projects, yet, the sub-projects are not (but can be) available as templates in the new project menu themselves. This is great if you are trying to template something like an enterprise design that is dependent on many projects working together, but you don’t want the user to be able to create these sub projects, or you want them to be available in a different project template area/category.
Steps:
- Create a folder “MyTemplate”
- Create a root.vstemplate file
Add the following to the file:
<WizardExtension> <Assembly>NuGet.VisualStudio.Interop, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</Assembly> <FullClassName>NuGet.VisualStudio.TemplateWizard</FullClassName> </WizardExtension> <WizardData> <packages repository="extension" repositoryId="fill this in"> <package id="Newtonsoft.Json" version="5.0.6" /> </packages> </WizardData>
Open your first project you wish to use as a “sub project” template, export template from File->Export Template.
- Extract the zip contents to your MyTemplate folder, so you end up with MyTemplate/Project1
- Open up the Project1.vstemplate from what you just extracted.
and paste in the following below the TemplateContent block (for example if you want to add a Json nuget package)
<WizardExtension> <Assembly>NuGet.VisualStudio.Interop, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</Assembly> <FullClassName>NuGet.VisualStudio.TemplateWizard</FullClassName> </WizardExtension> <WizardData> <packages repository="extension" repositoryId="fill this in"> <package id="Newtonsoft.Json" version="5.0.6" /> </packages> </WizardData>
Zip up your entire root folder MyTemplate, so you end up with MyTemplate.zip which has the contents of the MyTemplate folder.
- Create a VSIX project (you will need Visual Studio 2012 SDK to have this template) from the Extensibility template category under C#.
- Create a packages folder
- Add the nuget package (.nupkg file only) you referenced in your sub projects vstemplate to the packages folder and in the files properties, set its build action to content, and Include in VSIX to true. In my case I added Newtonsoft.Json.5.0.6.nupkg.
- In the source.extension.vsixmanifest set the Author name
- In the Assets tab, click new and select project template from the drop down, then file on file-system in the next drop down.
- Browse and select the zip you created, hit Ok. This will create a ProjectTemplates Folder with the zip.
- Copy the Product Id from the top of the source.extension.vsixmanifest.
- Open up the zip with a program like WinRar that allows you to save changes directly to the zip (the default windows zip app does not allow this).
- Paste in the Product id into the repositoryid section
- Save the changes to the zip file (make sure you go back to WinRar if thats what you are using, as it will have detected the changes and will ask you if you wish to update)
- Build the solution and go to the bin/debug folder to run the vsix installer
- Create your project
Optional Step to have your master project rename your files and namespaces
- Open each sub project vstemplate file, and add $safeprojectname$ to the DefaultName Element. e.g.
<DefaultName>$safeprojectname$.Domain</DefaultName>