简体   繁体   中英

Include T4 generated files on the same folder of the template file

I'm trying to add a saved file to the current project of my T4 template file. The file is saved as expected by the SaveOutput method, but when I use the IncludeInCurrentProject method, that calls the ProjectItems.AddFromFile ( docs here ), and then the file is added on the root of the project.

I'd like to include the file generated by the SaveOutput method on that exactly location on the project.

This is what I have right now:

在此处输入图片说明

Here is my .tt file:

<#@ template debug="true" hostspecific="true" language="C#" #>
<#@ output extension=".sql" #>
<#@ assembly name="Microsoft.VisualBasic.dll" #>
<#@ assembly name="EnvDTE" #>
<#@ import Namespace="System.IO" #>
<#@ import namespace="EnvDTE" #>

<#
    var MigrationName = Microsoft.VisualBasic.Interaction.InputBox("InputBox Label", "Description");
    if (string.IsNullOrWhiteSpace(MigrationName))
        return "";

    var MigrationVersion = System.DateTime.Now.ToString("yyyyMMddHHmm");
    var MigrationFileName = MigrationVersion + "-" + MigrationName + ".sql";
    var MigrationFilePath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Host.TemplateFile), "", MigrationFileName));
#>

My T4 template goes here

<#
SaveOutput(MigrationFilePath);
IncludeInCurrentProject(MigrationFilePath)
    .Open(Constants.vsViewKindPrimary)
    .Activate();
#>
<#+
    private void SaveOutput(string filename)
    {
        File.WriteAllText(filename, GenerationEnvironment.ToString());
        GenerationEnvironment.Clear();
    }

    private ProjectItem IncludeInCurrentProject(string filename)
    {
        return CurrentProject.ProjectItems.AddFromFile(filename);
    }

    private Project CurrentProject
    {
        get 
        {
            if (_currentProject == null) {
                var serviceProvider = (IServiceProvider)this.Host;
                var dte = serviceProvider.GetService(typeof(DTE)) as DTE;

                foreach(Project project in dte.Solution.Projects) 
                {
                    // workaround. dte.Solution.FindProjectItem(Host.TemplateFile).ContainingProject didn't work
                     string projectPath = project.FullName.Replace("\\" + project.FileName, string.Empty);
                     if(Host.TemplateFile.Contains(projectPath))
                     {
                        _currentProject = project;
                        break;
                     }
                }
            }
            return _currentProject;
        }
    }


    private Project _currentProject;
#>

How can I include my generated files on the same folder of the T4 template file?

调用IncludeInCurrentProject时,输入应为路径+文件名。

The CurrentProject.ProjectItems always references the ProjectItems in the root.

I used the file path to navigate through the ProjectItems and call the AddFromFile on the correct one. You can check the GetCurrentProjectItem method, this behaviour is implemented there.

Now the template works fine:

<#@ template debug="true" hostspecific="true" language="C#" #>
<#@ output extension=".sql" #>
<#@ assembly name="Microsoft.VisualBasic.dll" #>
<#@ assembly name="EnvDTE" #>
<#@ import Namespace="System.IO" #>
<#@ import Namespace="System.Text.RegularExpressions" #>
<#@ import namespace="EnvDTE" #>

<#
    var migrationName = Microsoft.VisualBasic.Interaction.InputBox("InputBox Label", "Description");

    Regex alphaNumericRegex = new Regex("[^a-zA-Z0-9-_]");
    migrationName = alphaNumericRegex.Replace(migrationName, string.Empty);

    if (string.IsNullOrWhiteSpace(migrationName))
        return "";

    var migrationVersion = System.DateTime.Now.ToString("yyyyMMddHHmm");
    var migrationFileName = migrationVersion + "-InsertCourt" + migrationName + ".sql";
    var migrationFilePath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Host.TemplateFile), migrationFileName));
#>

My T4 template goes here

<#
SaveOutput(migrationFilePath);
IncludeInCurrentProject(migrationFilePath)
    .Open(Constants.vsViewKindPrimary)
    .Activate();
#>
<#+
    private void SaveOutput(string filename)
    {
        File.WriteAllText(filename, GenerationEnvironment.ToString());
        GenerationEnvironment.Clear();
    }

    private ProjectItem IncludeInCurrentProject(string filename)
    {
        ProjectItem item = GetCurrentProjectItem().ProjectItems.AddFromFile(filename);
        item.Properties.Item("BuildAction").Value = "None";
        return item;
    }

    private ProjectItem GetCurrentProjectItem()
    {

        var serviceProvider = (IServiceProvider)this.Host;
        var dte = serviceProvider.GetService(typeof(DTE)) as DTE;

        string templateDirectory = Path.GetDirectoryName(Host.TemplateFile);
        string foldersString = templateDirectory.Replace(Path.GetDirectoryName(GetCurrentProject().FullName), string.Empty);
        string[] foldersArray = foldersString.Split(new [] {"\\"}, StringSplitOptions.RemoveEmptyEntries);

        foreach(Project project in dte.Solution.Projects) 
        {
            ProjectItems currentProjectItems = null;

            foreach(string folder in foldersArray)
            {
                if(currentProjectItems == null) 
                {
                    currentProjectItems = project.ProjectItems;
                }

                foreach(ProjectItem projectItem in currentProjectItems) 
                {
                    if(projectItem.Name == folder) 
                    {
                        if(Array.IndexOf(foldersArray, folder) == foldersArray.Length - 1)
                        {
                            return projectItem;
                        }
                        currentProjectItems = projectItem.ProjectItems;
                        break;
                    }
                }
            }
        }
        return null;
    }

    private Project GetCurrentProject()
    {
        var serviceProvider = (IServiceProvider)this.Host;
        var dte = serviceProvider.GetService(typeof(DTE)) as DTE;

        foreach(Project project in dte.Solution.Projects) 
        {
            // workaround. dte.Solution.FindProjectItem(Host.TemplateFile).ContainingProject didn't work
            string directory = Path.GetDirectoryName(project.FullName);
            if(Host.TemplateFile.Contains(directory))
            {
                return project;
            }
        }
        return null;
    }


    private ProjectItem _currentProjectItem;
#>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM