How to create multiple output files from a single T4 template using Tangible Editor?
Asked Answered
D

3

14

I tried to follow this tutorial: http://t4-editor.tangible-engineering.com/blog/how-to-generate-multiple-output-files-from-a-single-t4-template.html

with visual studio 2015 (.Net 4.5)

Sample project with error: http://www.filedropper.com/t4fail


I created the Template1.tt with the following source:

<#@ include file="TemplateFileManagerV2.1.ttinclude" #>
<#@ Assembly Name="System.Core" #>
<#@ Assembly Name="System.Windows.Forms" #>
<#@ import namespace="System" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Diagnostics" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.Collections.Generic" #> 
<#
    var manager = TemplateFileManager.Create(this);
#>

I added TemplateFileManagerV2.1.ttinclude from template gallery to my project.

Then I got an error:

'Microsoft.VisualStudio.TextTemplating.IDebugTextTemplatingEngine' is defined in an assembly that is not referenced. You must add a reference to assembly 'Microsoft.VisualStudio.TextTemplating.Interfaces.11.0, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.

So I added references to

C:\Windows\Microsoft.NET\assembly\GAC_MSIL\Microsoft.VisualStudio.TextTemplating.11.0\v4.0_11.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.TextTemplating.11.0.dll

and

C:\Windows\Microsoft.NET\assembly\GAC_MSIL\Microsoft.VisualStudio.TextTemplating.Interfaces.11.0\v4.0_11.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.TextTemplating.Interfaces.11.0.dll

to my project, but nothing changed.


The error was in the following method inside .ttinclude

public string GetTemplateContent(string templateName, TextTemplatingSession session)
    {
        string fullName = this.Host.ResolvePath(templateName);
        string templateContent = File.ReadAllText(fullName);

        var sessionHost = this.Host as ITextTemplatingSessionHost;
        sessionHost.Session = session;

        Engine engine = new Engine();
        return engine.ProcessTemplate(templateContent, this.Host);
    }

I replaced it with

public string GetTemplateContent(string templateName, TextTemplatingSession session)
    {
        string fullName = this.Host.ResolvePath(templateName);
        string templateContent = File.ReadAllText(fullName);

        var sessionHost = this.Host as ITextTemplatingSessionHost;
        sessionHost.Session = session;

        //Engine engine = new Engine();
        return "";//engine.ProcessTemplate(templateContent, this.Host);
    }

to check if the problem is indeed in dll and got:

'Microsoft.VisualStudio.TextTemplatingA30AC8B57EFC4307E43667FCD72F5E4857F498C5224AE0D43FFC74B3A98D4FA090794EF196648D62B1BC664AFBA5EDE831067D7D1768A759EBBE83426975F7AA.GeneratedTextTransformation' does not contain a definition for 'Host' and no extension method 'Host' accepting a first argument of type 'Microsoft.VisualStudio.TextTemplatingA30AC8B57EFC4307E43667FCD72F5E4857F498C5224AE0D43FFC74B3A98D4FA090794EF196648D62B1BC664AFBA5EDE831067D7D1768A759EBBE83426975F7AA.GeneratedTextTransformation' could be found (are you missing a using directive or an assembly reference?)

It seems, that it's not.

Doordie answered 6/11, 2015 at 20:44 Comment(2)
the error is pretty much telling you what the issue is and what you need to do.. whenever it states that a using directive or assembly reference can't be found.. then you need to do 2 of the following things. make sure that 1 add a using directive to the .cs file header 2 manually add the .dll to the references node in the project. if you are deploying also make sure that you set the CopyLocal property of the dll in the reference node = true.Labret
There is no .cs file. There is <#@ import namespace="Microsoft.VisualStudio.TextTemplating" #> directive on top of .ttinclude There is Microsoft.VisualStudio.TextTemplating.Interfaces.11.0.dll referenced by project. The error persists. (If you are about the first one)Doordie
D
8

<#@ template hostSpecific="true"#>

on top of .tt file solves everything.

Doordie answered 7/11, 2015 at 3:9 Comment(1)
This does not answer the question and should be down voted. As mentioned this answers the question #55297044Silencer
E
39

I remember I found an easier way to do it back in 2010, but now, after looking across the web for that method, I couldn't find it again. So, after some digging, I managed to find it in an old source code repository. Here's how I did it back then, without making use of any external file or dependency:

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System" #>
<#@ import namespace="System.IO" #>
<#@ output extension=".txt" #>
<#
for (Int32 i = 0; i < 10; ++i) {
#>
Content <#= i #>
<#
  // End of file.
  SaveOutput("Content" + i.ToString() + ".txt");
}
#>
<#+
private void SaveOutput(string outputFileName) {
  string templateDirectory = Path.GetDirectoryName(Host.TemplateFile);
  string outputFilePath = Path.Combine(templateDirectory, outputFileName);
  File.WriteAllText(outputFilePath, this.GenerationEnvironment.ToString()); 
  this.GenerationEnvironment.Remove(0, this.GenerationEnvironment.Length);
}
#>

Please note that I don't know who the original author of this method is. If you happen to know who he or she is, please leave a comment.

Edda answered 3/6, 2017 at 5:1 Comment(3)
This is a step in the right direction. May want to put your .tt file in a subdirectory so that generated files will be readily grouped. Be sure to toggle "Show all Files" off and on after adding new output files. Generated files must use Add to Project to make them compile.Tinfoil
@MicahEpps can you give an example of how to do that? All i get in my search is a regex inside the csproj. I'm pretty sure there is another way of doing this while generating the files.Threat
@madks13, AFAIU, you just need to concatenate the desired path to the outputFilePath variable above. Like: string outputFilePath = Path.Combine(templateDirectory, "My Folder", outputFileName); Then you can do what Micah said: Show All Files and add them to the project.Edda
D
8

<#@ template hostSpecific="true"#>

on top of .tt file solves everything.

Doordie answered 7/11, 2015 at 3:9 Comment(1)
This does not answer the question and should be down voted. As mentioned this answers the question #55297044Silencer
G
1

This is the documentation from Tangible Engineering:

https://t4-editor.tangible-engineering.com/blog/how-to-generate-multiple-output-files-from-a-single-t4-template.html

It requires you to include and use the Template File Manager. The steps are briefly as follows:

  • Obtain the file manager from their free code gallery (https://t4-editor.tangible-engineering.com/Download_T4Editor_Plus_ModelingTools.html)
  • Include the file manager in the main template file:
    <#@ include file="TemplateFileManagerV2.1.ttinclude" #>
  • Instantiate a manager:
    <# var manager = TemplateFileManager.Create(this); #>
  • Use the manager to start a new file:
    <# manager.StartNewFile("Outputfile2.txt"); #>
    Note that this will end a previously started file before starting the next.
  • Generate template code as normal (will be generated in new file until another file is started or files are processed below)
  • Finalize all files (will end previously started file):
    <# manager.Process(); #>

Also, this method will automatically add the new files to the project.

Update -- pics included

Part 1: Generate multiple output files

Create your template

Create your template

Include reusable Template Manager from Template Gallery

Include reusable Template Manager from Template Gallery (pt. 1)

Include reusable Template Manager from Template Gallery (pt. 2)

Include reusable Template Manager from Template Gallery (pt. 3)

Test the output to multiple files

Test the output to multiple files (pt. 1)

Test the output to multiple files (pt. 2)

Part 2: Multiple output files in different projects

enter image description here

Gumma answered 25/7, 2019 at 13:57 Comment(2)
Article includes image links which my browser is rejecting for security reasons.Subordinary
And it's proprietary. And it requires adding an extension.Cervin

© 2022 - 2024 — McMap. All rights reserved.