Thursday, September 07, 2006

Fustrating Visual Studio Templates

VS 2005 has a new template feature that allows you to easily create item and project templates that you can add to the 'new item' and 'new project' dialogue boxes. It's pretty cool, you just select an item or a project from an existing solution and click file->Export template, a wizard pops up that allows you to name the template and optionally deploy it. Scott Guthrie has a nice post about it on his excellent blog (a required read for .net developers). As well as projects and items there's also a multi-project template that you're supposed to be able to use to produce template solutions. I've been playing with this for last couple of days in order to create a web service solution template for our team and it's pretty disapointing. Not much thought seems to have gone into it and there are two things in particular that make it useless for me. First of all, there's no way of customising the name of the projects in the solution. In the new solution dialogue you can choose the name of your solution and most .net projects I've worked on also use this as a solution namespace. Usually you name the projects in the solution prefixed with the solution name which plays well with the default namespace behaviour in visual studio. For example, say I call my solution 'Mike.MegaThing'. I'd then name my projects things like, 'Mike.MegaThing.Domain', 'Mike.MegaThing.Service', 'Mike.MegaThing.Dal'. Now every time I create a new class in 'Mike.MegaThing.Domain', the namespace is automatically created as 'Mike.MegaThing.Domain', perfect. Unfortunately the multi-project-template has no way of allowing you to change the name of it's projects. Although template items, like classes, can be tokenised and expanded with a range of default parameters like $safeprojectname$ this doesn't apply to the .vstemplate files themselves. My solution template has to have fixed project names like 'Service' or 'Domain' with similar default namespaces, which is crap because I want 'Mike.MegaThing.Dal' to be in a different namespace to 'Mike.LittleThing.Dal'. The other thing which makes the multi-project template useless is the wierd way it creates the folder structure for your created solution. Normally, if you add a project to a solution it creates a sub folder under your solution folder with the project name and puts the .csproj file in there. The multi-project template doesn't do this, instead it creates a sub folder under the solution folder with the name of the solution and then creates the project folders in that. There seems to be no way of altering this behaviour. So, thumbs down to visual studio templates for creating template solutions, although if you just want simple project or item templates it's perfectly adequate. I'm now going to be digging into the Guidance and Automation Toolkit (GAT) which looks much closer to what I need, more soon.


Anonymous said...

After digging several days into the multi-project template, I discovered exactly the same things... There seems to be no way of setting the default namespace of the projects in your template-solution, and it seems impossible to alter the weird directory structure...

Anonymous said...

Found a nice workaround as a post processing step with the WizardExtension/IWizard combination:
* In the projects I modify the replacementsDictionary["$safeprojectname$"] in the RunStarted to solve the namespace issue.
* I save the solution on the correct location via dte.Solution.SaveAs in the RunFinished.

Mike Hadlow said...


Thanks for the tip!


Anonymous said...

Where do you get the dte object from? when you implement the IWizard class, it doesn't seem like you can get the dte object to use Solution.SaveAs(...);

Anonymous said...

Hello group, I have a sticky Multi-Project Template (MPT) problem I'm sure many others are having. I need to parameterize individual projects in a MPT; I want to substitute various custom parameters (like Namespace names in code), but it only seems to work for SPTs.

I've found that you can add the "CustomParameters" element to a MPT VSTEMPLATE file, but that's it. These parms don't make it into the "RunStarted.replacementsDictionary" (which they do in a SPT), and when added to the Dictionary via Wizard code in "RunStarted", they aren't substituted in any of the projects i nan MPT Wizard as they are in a SPT Wizard.

It appears that the problem is, certain Wizard functions aren't called during the execution for an MPT. More accurately, it appears that there aren't "escapes" by VS into your Wizard at t ehdesired moments, so for example, the end of the entire solution generation is only when "ProjectFinishedGenerating" is entered for example, and then the "Project" type passed in is null. Seems like the "events" (in this case methods) are not fired for each successive project in an MPT.

Is there a way to circumvent this problem, is a fix coming (perhaps with more events and better control for MPTs), or is there a way to tap into the VS SDK during template generation?

It'd also be cool if there was a way to open a CSPROJ file, edit it, and replace what was deployed by the Wizard/VS (w/out VS giving you the "this thing was changed outside the env; reload?" msg); at least I could make necessary changes in the CSPROJ files themselves. Again, this is probably something that having more "call-ins" at strategic points by Visual Studio during the generation might fix.

Anyway thanks in advance!

Anonymous said...

@Dan: You can cast the automationObject to _DTE from the RunStarted method.