【问题标题】:Include T4 generated files on the same folder of the template file在模板文件的同一文件夹中包含 T4 生成的文件
【发布时间】:2019-09-03 15:12:01
【问题描述】:

我正在尝试将保存的文件添加到我的 T4 模板文件的当前项目中。 SaveOutput方法按预期保存文件,但是当我使用IncludeInCurrentProject方法时,调用ProjectItems.AddFromFiledocs here),然后将文件添加到root 项目。

我想将SaveOutput 方法生成的文件包含在项目的确切位置上。

这就是我现在拥有的:

这是我的 .tt 文件:

<#@ 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;
#>

如何将我生成的文件包含在 T4 模板文件的同一文件夹中?

【问题讨论】:

    标签: c# visual-studio t4


    【解决方案1】:

    CurrentProject.ProjectItems 始终在根目录中引用 ProjectItems

    我使用文件路径浏览ProjectItems 并在正确的路径上调用AddFromFile。你可以检查GetCurrentProjectItem方法,这个行为是在那里实现的。

    现在模板可以正常工作了:

    <#@ 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;
    #>
    

    【讨论】:

    • 我遇到了完全相同的问题,但是从另一个项目创建文件时。我采用了您的文件夹循环解决方案,它就像一个魅力。谢谢!
    • @Andrea 很高兴该解决方案对您有所帮助。
    【解决方案2】:

    当您调用 IncludeInCurrentProject 时,输入应该是路径 + 文件名。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-16
    • 1970-01-01
    • 2020-06-22
    • 1970-01-01
    • 2011-05-10
    • 2012-06-13
    相关资源
    最近更新 更多