T4 Templates and Runtime Options

I am creating a plugin in VS 2010 and I am obsessed with the T4 generation. I have now implemented (e.g. MSDN) a T4 user host to generate my T4 results, and I use it as follows:

const string content = @"c:\Simple.tt"; var engine = new Engine(); var host = new MyTemplateHost(); var result = engine.ProcessTemplate(File.ReadAllText(content), host); foreach (CompilerError error in host.Errors) { Console.WriteLine(error.ErrorText); } 

This works until I pass the parameter in the template. As soon as I create the parameter in the .tt file, the Host fades away, saying that it does not know how to resolve it. I saw that you can use TemplateSession for this, but I did not understand how to pass it to my host? Is there a better way to generate code from .tt using C # and passing parameters at runtime? Maybe I'm wrong.

+8
c # template-engine visual-studio-2010 t4
source share
6 answers

In Visual Studio 2010, the T4 template engine has been radically changed. Now you can directly run the template file and pass it any parameter you want.

  var template = Activator.CreateInstance<SimpleTemplate>(); var session = new TextTemplatingSession(); session["namespacename"] = "MyNamespace"; session["classname"] = "MyClass"; var properties = new List<CustomProperty> { new CustomProperty{ Name = "FirstProperty", ValueType = typeof(Int32) } }; session["properties"] = properties; template.Session = session; template.Initialize(); 

This statement processes the following pattern:

 <#@ template language="C#" debug="true" #> <#@ output extension=".cs" #> <#@ assembly name="System.dll" #> <#@ import namespace="System" #> <#@ import namespace="System.Collections.Generic" #> <#@ import namespace="SampleDomain.Entities" #> <#@ parameter name="namespacename" type="System.String" #> <#@ parameter name="classname" type="System.String" #> <#@ parameter name="properties" type="System.Collections.Generic.List<CustomProperty>" #> using System; using System.Collections.Generic; using SampleDomain.Entities; namespace <#= this.namespacename #> { public class <#= this.classname #> 

So honestly, the owner is no longer needed ...

+12
source share

If you are creating an add-in for VS, you probably do not need a special host, but instead you can use the built-in VS host through its service interface.

Mark ITextTemplating as the main service API that you can get by dropping your DTE object on the IServiceProvider and then calling GetService (typeof (STextTemplating))

To pass parameters, you can then skip the ITextTemplating object in ITextTemplatingSessionHost and set the ITextTemplatingSession property for the Session property. A session is just a serializable bag of properties. There, the trivial version is presented as TextTemplatingSession .

+7
source share

Add and implement ITextTemplatingSessionHost on your own host. The simple implementation of ITextTemplatingEngineHost will not give you session support.

  [Serializable()] public class CustomCmdLineHost : ITextTemplatingEngineHost,ITextTemplatingSessionHost { ITextTemplatingSession session = new TextTemplatingSession(); public ITextTemplatingSession CreateSession() { return session; } public ITextTemplatingSession Session { get { return session; } set { session = value; } } 
+6
source share

Using T4 Templates to Generate Runtime

  • You choose this method if you need to generate code at runtime. For example, you want to generate a page object using Selenium.

    enter image description here

  • Create a folder in your solution, name it Templates (good name for T4 Templates).

  • Then add a new element, type T4, then select Temporary text template .... We named our template MyNodeName.tt, which is shown in the image above.

  • Add your code as shown below, the upper part was inserted by Visual Studio ...

Add code

You can see what we want to pass in the namespace and ClassName (this is the markup Model.NameSpaceName and Model.ClassName seen above.

The hard part is learning how to pass parameters ...

Create a new CS class named partial in the file name.

Partial file name

But in the class do not call this name MyNodeNamePartial this is the name MyNodeName:

  public partial class MyNodeName { public MyNodeNameModel Model { get; set; } } 

This is the same name as the TT file. (MyNodeName), which creates its own partial class. But now notice that we have a MODEL value for this class type.

  public class MyNodeNameModel { public MyNodeNameModel() { ClassName = "Test"; } public string ClassName { get; set; } public string NameSpaceName { get; set; } } 

The model class contains ClassName and NameSpaceName and all that you want to "insert" into the template.

The key to work shown is that a text runtime template was used! If you use a text template, no matter what you do, you will see errors similar to โ€œModel not foundโ€ or other controversial problems.

Debugging Tips: โ€œThe model cannot be foundโ€ is the T4 generation code telling you that in your partial class with the MODEL variable that it cannot find! Check both partial and model types to make sure they are in the same namespace as any other namespace of regular classes, if created in this folder.

+4
source share

See the MSDN Link (section "Passing Parameters in the Designer").

Summarizing:

Create a partial class with the same name of your TT file.

 partial class MyWebPage { private MyData m_data; public MyWebPage(MyData data) { this.m_data = data; }} } 

Then just pass your parameters in the class constructor

 MyWebPage page = new MyWebPage(data); String pageContent = page.TransformText(); 
+1
source share

Figured it out. For interested parties, see the following:

http://www.olegsych.com/2009/09/t4-preprocessed-text-templates/

0
source share

Source: https://habr.com/ru/post/649995/


All Articles