Creating custom multi-project templates for Visual Studio is hard. There’s lots of tricky stuff you need to do in order for your template to have a decent physical and solution structure. I wrote a tool to help you with that.
Enter solution-snapshotter – a tool that automatically exports a given solution as a Visual Studio template. It takes care of preserving your solution and folder structure, and also keeps any extra non-project files you may have such as configurations, ruleset files, etc. The generated template will be packaged in a Visual Studio extension for easy installation and distribution.
Go straight to the repo to see it in action or read the rest of the article for a more detailed explanation on what problems does it solve and how you can use it.
Solution Snapshotter – Visual Studio tool
Have you ever found yourself setting up the same project structure, using the same framework, the same ORM, the same logging library – over and over again?
I know I have.
This can potentially take up days until you get every tiny detail right.
When you’re using .NET with Visual Studio and you find yourself setting up projects often, the logical solution would be to automate this process through a Visual Studio template. Like one of these:
To create such a template, there’s an Export Template button under the Project menu (on the top) inside Visual Studio.
It creates a .zip file that you have to place inside the “%USER%/Documents/Visual Studio/Templates/ProjectTemplates” folder. After doing that, you’ll have your project available as a template.
The problem with Visual Studio Export
Visual Studio export works only for single assemblies that don’t reference anything else, but you’d rarely see a setup as simple as that.
Most modern projects adopt a multi-assembly approach, with solution structures often looking similar to this:
And folder structures looking similar to this:
You can have templates like that. They are called multi-project templates.
The problem is that when you attempt to create one, things get unnecessarily complicated.
Through the rest of the article, we’ll go over the creation of such templates and the numerous caveats that appear during the process.
Are you a .NET/C# developer looking for a resource covering New Technologies, in-depth Tutorials and Best Practices?
Well, you are in luck! We at DotNetCurry release a digital magazine once every two months aimed at Developers, Architects and Technical Managers and cover ASP.NET Core, C#, Patterns, .NET Core, ASP.NET MVC, Azure, DevOps, ALM, TypeScript, Angular, React, and much more. Subscribe to this magazine for FREE and receive all previous, current and upcoming editions, right in your Inbox. No Gimmicks. No Spam Policy.
Click here to Download the Magazines For Free
Creating multi-project templates
Say you have the solution similar to the one we just saw and you have already set up various tools such as XUnit, EntityFramework, Swagger, StyleCop, authentication/authorization, etc. You would like to export the solution as a template so you can reuse the setup for other projects.
It shouldn’t be a big deal, right? Let’s check for ourselves.
Note: This particular project setup is available on the VS Marketplace. It is automatically generated from this source project using solution-snapshotter – the tool we’ll be introducing.
Note: The content that follows is not meant to be a tutorial on how to create multi-project templates. Don’t worry if you feel lost at any point. For the more curious among you, I’ll be providing links where you can get additional info on things that we’ll simply skim over. The main points are: there’s lots of tricky stuff to do; you can avoid doing it by using the tool which we’ll introduce later.
The documentation for creating multi-project templates recommends us to use the built-in Export Template functionality for each project in our solution. We should then combine the exported project templates into a single, multi-project template using a special .vstemplate format.
After doing this for the setup that we introduced, we get to a folder looking like this:
Each MyProject.* folder is a project template that was exported by Visual Studio. What we did is simply place them into a single directory. We also wrote the MyProjectTemplate.vstemplate file. It is what unites everything into a single, multi-project template. Its contents are the following:
After zipping everything and placing it into Visual Studio’s ProjectTemplates folder, we have our template available.
Let’s use it to create a project called TestTemplateProject.
Structure-wise, it looks okay. However, if we try to build it, we’ll quickly find out that the references are all broken!
You see, our initial project had a clean and tidy folder structure, like this:
However, when using the built-in Export Template functionality, Visual Studio ignores all that and just flattens the structure like so:
It doesn’t care to fix the reference paths inside the .csproj files that were meant for the original folder structure, thus they get broken.
Through the error messages, we can also see that the reference names haven’t been updated. Even though we’ve named our new project TestTemplateProject, the references in the .csproj files are all looking for assemblies named MyProject.*, which was the original project name.
Caveat 1: Custom physical folder structure
The bad news is, the multi-project template format does not support custom physical folder structures.
The good news is, we can work around that by packaging our template into a Visual Studio extension (VSIX). This will allow us to plug in during the project creation phase and execute custom logic using the IWizard interface.
Note: I won’t get too much into how you can package your template or use the IWizard interface as that will bloat the article significantly. If it interests you, there’s a tutorial on packaging in the docs. After getting through it, read about using wizards. Then, you’ll need to get familiar with the _Solution interface and its derivatives – Solution2, Solution3, and Solution4. Overall, working with these is clumsy. You often need to resort to explicit typecasts and try-catch blocks. If you’re looking into it, these extension methods will come in handy.
After packaging your template in a Visual Studio extension project, you’ll have something similar to this:
You can build this project to get a .vsix file, which you can run to install the extension to Visual Studio instances of your choice.
After installing the built .vsix, the template will become available in Visual Studio.
Again, there are quite a few steps to get to this point. We will not be digging further into those. Our goal is to just skip over to the largest issues that arise during the template creation process. This is so we can then clearly see how and why those issues are solved using solution-snapshotter – the tool we’ll introduce at the end of the article.
If you would like to learn more about the manual process, the docs are a decent starting point.
We’re continuing the article under the following assumptions: we’ve successfully packaged our template into a VSIX; we’ve successfully implemented custom logic that creates a correct folder structure and rearranges our projects correspondingly; we’ve successfully fixed the broken reference paths; we’ve successfully installed the VSIX to Visual Studio.
Our newly packaged template
Here is how our template looks after installing.
Let’s create a new project out of it called TestVSIXTemplate.
Looks pretty nice, we can also see that the generated folder structure is correct.
But again, even though we’ve fixed the folder structure and references… it doesn’t build.
Caveat 2: Extra files and folders
We can see from the error message that the stylecop.json file is missing. In the initial project, this file was placed in a separate folder called configuration. It wasn’t directly referenced by any .csproj, but instead was added as a link.
The configuration folder is however, missing. This is because when we initially exported each project using Export Template, any extra files were lost. The .vstemplate format only allows you to include files that are directly referenced by the .csproj files.
Again, there’s a workaround.
Since we’ve packaged our template into a Visual Studio extension and Visual Studio extensions are simply .NET assemblies, we can include any extra files we like by either embedding them or including them as assets. They can be then unpacked during the folder structure creation using custom logic placed inside the IWizard interface implementation.
Not a very pleasant development experience.
Caveat 3: Maintenance
Even if we do all of the above correctly, we still have to maintain the template. That brings us to another problem.
The template we have is no longer a runnable project, but instead is a bunch of tokenized source files similar to this one.
This means that any changes we make, we can’t compile and test. Testing is done by:
- Updating the template (means digging around broken files)
- Updating the VSIX
- Running the VSIX inside an experimental Visual Studio instance
- Creating a new project with the template
- Verifying everything works as expected
Great if you want to spend 30 minutes updating a NuGet package and moving a few classes.
Forget all about this – use solution-snapshotter
All of the aforementioned problems are real. I encountered them while building and maintaining the Dev Adventures template.
And it never felt right. It always seemed to me that all of this VSIX mumbo jumbo should happen automatically inside a CI/CD pipeline.
This led me to write a tool that automatically does everything for you. It takes an initial project source and gives you a ready to go VSIX project that has your project packaged as a template. And it takes care of all the mentioned issues!
Your physical folder structure, references and extra files will be preserved without writing a single line of code. Just run solution-snapshotter.exe and enjoy the magic.
See the Dev Adventures template extension. It is now 100% automatically generated and published to the VS Marketplace. You can check out the source repository here. Note the input.config file, that’s all you really need.
solution-snapshotter is open-source and written in F#. You can visit the GitHub repo by going to this link. The usage is very simple, the readme should be enough to get you started.
How can it help, you may ask? Let’s see.
For the setup that we introduced in the beginning..
..we can simply call solution-snapshotter.exe. (see the Minimal Usage section for a download link and a command you can test with)
..and receive a ready-to-go VSIX project!
We can build it.
And receive our .vsix installer.
After installing, the template will become available inside Visual Studio!
We can use it to create a new project.
..and have our setup ready in moments!
And of course, with all references being valid!
If you’re working for a service company, use solution-snapshotter to create and maintain standard templates for different project types.
If you’re doing microservices, use it to create common templates for services and shared libraries.
Or if you just finished setting up a great project, use it to share it with the world by extracting a template and shipping it to the VS Marketplace.
Again, solution-snapshotter is open-source! All contributions and feedback are most welcome. Don’t hesitate to open an issue if there’s anything you think can be improved.
Enjoy your headache-free templates!
The entire source code of this tool is available at Github.
This article was technically reviewed by Yacoub Massad
This article has been editorially reviewed by Suprotim Agarwal.
C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.
We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).
Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.
Click here to Explore the Table of Contents or Download Sample Chapters!