How to include 'Solution Items' files in multi-project solution template
Asked Answered
P

1

13

I am trying to create a multi-project solution template for Visual Studio 2019. I can successfuly add multiple project in multiple folders.

As a next step, I would like to add local files to the root of the solution or even in folders such as .gitignore, nuget.config,... files, but so far no luck.

Below is my .vstemplate file, the commented lines are the files I am trying to add. I have tried it this way, putting the lines in a <SolutionFolder> block, putting them outside of the ProjectCollection block,...

<VSTemplate Version="3.0.0" Type="ProjectGroup" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005">
  <TemplateData>
    <Name>Test Application</Name>
    <Description>A project template for creating a basic Test Application</Description>
    <ProjectType>CSharp</ProjectType>
    <ProjectSubType>
    </ProjectSubType>
    <SortOrder>1000</SortOrder>
    <CreateNewFolder>false</CreateNewFolder>
    <DefaultName>MaestroApp</DefaultName>
    <ProvideDefaultName>true</ProvideDefaultName>
    <LocationField>Enabled</LocationField>
    <EnableLocationBrowseButton>true</EnableLocationBrowseButton>
    <BuildOnLoad>true</BuildOnLoad>
    <Icon>M.png</Icon>
  </TemplateData>
  <TemplateContent>
    <ProjectCollection>
<!--
        <ProjectItem ReplaceParameters="false" TargetFileName=".gitattributes">.gitattributes</ProjectItem>
        <ProjectItem ReplaceParameters="false" TargetFileName=".gitignore">.gitignore</ProjectItem>
        <ProjectItem ReplaceParameters="false" TargetFileName="directory.build.props">directory.build.props</ProjectItem>
        <ProjectItem ReplaceParameters="false" TargetFileName="nuget.config">nuget.config</ProjectItem>
        <ProjectItem ReplaceParameters="false" TargetFileName="README.MD">README.MD</ProjectItem>-->
      <SolutionFolder Name="Documents" CreateOnDisk="true"></SolutionFolder>
      <SolutionFolder Name="src" CreateOnDisk="true">
        <ProjectTemplateLink ProjectName="$projectname$" CopyParameters="true">
          MaestroApplicationTemplate\MyTemplate.vstemplate
        </ProjectTemplateLink>
        <ProjectTemplateLink ProjectName="$projectname$.Data" CopyParameters="true">
          MaestroApplicationTemplate.Data\MyTemplate.vstemplate
        </ProjectTemplateLink>
        <ProjectTemplateLink ProjectName="$projectname$.ProcessEngine" CopyParameters="true">
          MaestroApplicationTemplate.ProcessEngine\MyTemplate.vstemplate
        </ProjectTemplateLink>
      </SolutionFolder>
      <SolutionFolder Name="Test" CreateOnDisk="true">
      </SolutionFolder>
    </ProjectCollection>
  </TemplateContent>
</VSTemplate>

Any help would be greatly appreciated!

Purpure answered 16/4, 2019 at 9:16 Comment(5)
Did you ever find an answer to this? It's pretty weird that this is not easily doable out of the box...Lopez
No I didn't. I decided to create a dotnet template to scaffold my applications. See: learn.microsoft.com/en-us/dotnet/core/tools/custom-templatesPurpure
Hi, I am also stuck at the same point, can you share your example which u did via custom templates. Are you able to create a visual studio project template where you are copying the .gitignore files along with the project?Topsail
@ArnaudVdP would you have an example of what you were doing please?Mistletoe
@Topsail No in the end, I wasn't able to copy the .gitignore files along with the project. That is why I chose to make a dotnet template.Purpure
G
1

I know you were asking about a .vstemplate, but I figure since dotnet new templates are more appropriate nowadays, let me answer how to do it there (because it requires a bit of tinkering as well):

I'm assuming you've built the solution as you want it, added all solution files, etc. Then you've added a template.json as described in the documentation.

The next step is to make sure the template JSON has solution as the type, as opposed to the usual "project":

"tags": {
  "language": "C#",
  "type": "solution"
},

Also you need to ensure that the solution file is NOT named the same as the identity you've set in the template. Visual Studio does not like this and will overwrite the solution you provide with it's own, somehow loosing all solution files. I don't really know why.

So if your identity is set to BlazorServerApp like this:

"identity": "BlazorServerApp",

Then name the solution something like GeneratedSolution.sln. And then you add a modifier that will rename this solution to the correct name:

"sources": [
{
  "modifiers": [
  {
     "condition": "(HostIdentifier == \"dotnetcli\" ||  HostIdentifier == \"dotnetcli-preview\")",
       "rename": {
         "GeneratedSolution.sln": "BlazorServerApp.sln"
       }
     }
   ]
  }
],

Once that is done the template should behave nicely in both Visual Studio and dotnet new.

You may also have the problem that hidden files don't get included into the template, for example when trying to include an .editorconfig. There's a solution in another SO question.

Here is a complete example template.json:

{
  "$schema": "http://json.schemastore.org/template",
  "author": "Your Name",
  "name": "Blazor Server Application",
  "description": "A blazor server solution template",
  "identity": "BlazorServerApp",
  "shortName": "my-blazor-server",
  "classifications": [ "Web", "Blazor" ],
  "icon": "icon.png",
  
  "sourceName": "BlazorServerApp",
  "preferNameDirectory": true,

  "guids": [
    "53C5DAEE-6473-4825-87C2-46EBC88EBBD3",
    "E5E29BA4-B30E-46DD-A9F2-8378E685C5F8"
  ],
  
  "tags": {
    "language": "C#",
    "type": "solution"
  },
  
  "sources": [
    {
      "exclude": [
        ".idea/**",
        ".template.config/**",
        "**/node_modules/**/*"
      ],
      "modifiers": [
        {
          "condition": "(HostIdentifier == \"dotnetcli\" ||  HostIdentifier == \"dotnetcli-preview\")",
          "rename": {
            "GeneratedSolution.sln": "BlazorServerApp.sln"
          }
        },
        {
          "rename": {
            "editorconfig": ".editorconfig",
            "gitignore": ".gitignore"
          }
        }
      ]
    }
  ],
  
  "symbols": {
    "HostIdentifier": {
      "type": "bind",
      "binding": "HostIdentifier"
    }
  }
}

And here is a screenshot of the solution generated in Visual Studio, with all the solution files:

generated solution

Goods answered 15/6, 2023 at 7:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.