Search code examples
visual-studiovisual-studio-2017vsixvisual-studio-templates

How can I add files programmatically to a visual studio template?


I have created a visual studio project template for .net core applications. When creating a new project using this template I want to have the ability to select between Azure Authentication and Identity Authentication. In order to achieve this, I have created a wizard. Depending on the selected option on the wizard, some additional files must be included in the project. My problem is that I have no clue about how can I add those extra files to my project.

1st Approach

At first I created an Item Template and tried to add its contents to my project.

AzureAuthentication.vstemplate

<VSTemplate>
    <TemplateData>
        <!-- code removed for clarity -->
    </TemplateData>
    <TemplateContent>
        <Folder Name="Models" TargetFolderName="Models">
            <ProjectItem ReplaceParameters="true" TargetFileName="RefreshTokenResponse.cs">RefreshTokenResponse.cs</ProjectItem>
        </Folder>
        <Folder Name="Controllers" TargetFolderName="Controllers">
            <ProjectItem ReplaceParameters="true" TargetFileName="UserController.cs">UserController.cs</ProjectItem>
        </Folder>
    </TemplateContent>
</VSTemplate>

WizardImplementation.cs

public class WizardImplementation : IWizard {
    public void RunStarted(object automationObject, Dictionary<string, string> replacementsDictionary, WizardRunKind runKind, object[] customParams) {
        dte = automationObject as DTE;

        // code removed for clarity
    }

    public void ProjectFinishedGenerating(Project project) {
        switch (authenticationType) {
            default: break;
            case AuthenticationType.Azure: {
                    // code removed for clarity

                    using (StreamWriter writer = File.CreateText("C:/Users/pasjiannis.OFFICE/Desktop/log.txt")) {
                        dte.Solution.AddFromTemplate(templatePath, projectPath, "AzureAuthentication");
                    }

                    break;
                }
            case AuthenticationType.Identity: {
                    break;
                }
        }
}

This approach doesn't work at all.

2nd Approach

Then I converted my template from Item Template to Project Template.

AzureAuthentication.vstemplate

<VSTemplate>
    <TemplateData>
        <!-- code removed for clarity -->
    </TemplateData>
    <TemplateContent>
        <Project File="AzureAuthentication.csproj" ReplaceParameters="true">
            <Folder Name="Models" TargetFolderName="Models">
                <ProjectItem ReplaceParameters="true" TargetFileName="RefreshTokenResponse.cs">RefreshTokenResponse.cs</ProjectItem>
            </Folder>
            <Folder Name="Controllers" TargetFolderName="Controllers">
                <ProjectItem ReplaceParameters="true" TargetFileName="UserController.cs">UserController.cs</ProjectItem>
            </Folder>
        </Project>
    </TemplateContent>
</VSTemplate>

This worked partially. The files were added to my project successfully, but another project was also created to my solution.

3rd Approach

Instead of using the AddFromTemplate method in my WizardImplementation class, I tried to access my project, get the its project items and add the new items there like this

dte.Solution.Projects.Items(0).ProjectItems.AddFromFile("UserController.cs");

But ProjectItems on my Project is null.

What am I missing here? Is any of my approaches correct or is there a better way to achieve this?


Solution

  • I figured this out using my 3rd approach. I was missing the fact that dte.Solution.Projects.Items(0) was giving me the folder that contained my project, not the project itself.

    All I had to do is to change:

    dte.Solution.Projects.Items(0).ProjectItems.AddFromFile("UserController.cs");

    to

    dte.Solution.Projects.Items(0).SubProject.ProjectItems.AddFromFile("UserController.cs");