tag:blogger.com,1999:blog-1069012107309646352023-06-20T15:58:45.484+02:00OMS.Ice - T4 Text Template GeneratorOMS.Ice is an in-process T4 text template generator. It can be used to parse T4 text templates and to generate textual output at runtime. The OMS.Ice - T4 Text Template Generator has no dependencies to Visual Studio and can be deployed with your application.Unknownnoreply@blogger.comBlogger3125tag:blogger.com,1999:blog-106901210730964635.post-43084117864389321682012-06-16T09:34:00.001+02:002012-07-30T11:05:50.716+02:00Tutorial (part 2)<p>In the <a href="http://omsice.blogspot.de/2012/06/tutorial-part-1.html" target="_blank">first post</a> of this tutorial, we created a very simple T4 text template and generated a textual output containing the string <em>Hello World!</em>. In this second part I will show how you can add behavior to your T4 text template by using C#.</p> <p>We will start by using the T4 text template from part 1 of this tutorial.</p><pre class="brush: xml;"><#@ template language="C#" #><br />Hello World!</pre><br /><p>Additionally to saying “hello” to the world, we want to say hello to our friends Mary, Paul, and Peter. The simplest way to do this, would be just adding some new lines to the text template, but we would have to add a new line for each new friend. Therefore we need some logic inside the template that is able to process parameters passed to the T4 text template generator.</p><br /><p>In the C# code create a new list containing the names of our friends and pass this list to the Generate method of the T4 text template generator.</p><pre class="brush: csharp;">public static void Generate()<br />{<br /> IGenerator generator = new Generator();<br /><br /> var stream = new MemoryStream();<br /> var textWriter = new StreamWriter( stream );<br /><br /> IList<string> friends = new List<string> {"Mary", "Peter", "Paul"};<br /> generator.Generate(textWriter, Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"Part2\Part2.t4"), friends);<br /><br /> stream.Seek( 0, SeekOrigin.Begin );<br /> var textReader = new StreamReader( stream );<br /><br /> var generatedText = textReader.ReadToEnd();<br />}<br /></pre><br /><p>To read the parameters, the template needs a parameter directive for each parameter we pass to the T4 text template generator. Because we want to pass a list of names, the data type for the parameter is <font face="Courier New">IList<string></font>. The generic <font face="Courier New">IList</font> interface is not contained in the <font face="Courier New">System</font> namespace, thus we need an additional import directive for the <font face="Courier New">System.Collections.Generic</font> namespace. The import directive is the equivalent to the <font face="Courier New">using</font> statement in C# or the <font face="Courier New">imports</font> in VB.</p><pre class="brush: xml;"><#@ template language="C#" #><br /><#@ import namespace="System.Collections.Generic" #><br /><#@ parameter type="IList<string>" name="friends"#><br />Hello World!</pre><br /><p>To use control logic in a template or to generate dynamic text output, you have to add a control block. A control block is a part of a T4 text template that contains code. The code can be either C# or VB. The language must be specified in the language attribute of the template directive. T4 knows three different types of control blocks: Standard Control Block, Expression Control Block, and Feature Control Block. A standard control block is delimited by the T4 symbols <font size="2" face="Courier New"><#</font> ... <font size="2" face="Courier New">#></font> and can contain any valid C# or VB statements.</p><pre class="brush: csharp;"><# foreach(var friend in friends)<br /> {<br /> Write ( "Hello " + friend + "!\r\n" );<br /> } <br />#></pre><br /><p>In the above code we use the generator’s <font face="Courier New">Write</font> method to create the textual output. If the text becomes more complex, it would be better to use text blocks for the static parts of the output text and expression control blocks for the dynamic part. An expression control block is delimited by the T4 symbols <font size="2" face="Courier New"><#=</font> ... <font size="2" face="Courier New">#></font> and can contain C# or VB expressions.</p><pre class="brush: csharp;"><# foreach(var friend in friends)<br /> {<br />#><br />Hello <#= friend #>!<br /><# }<br />#></pre><br /><p>Finally we want to greet our friends in an alphabetical order. Therefore we add a feature control block containing a helper function that sorts out friends names. <br>A feature control block can contain properties or methods and is delimited by <font face="Courier New"><#+<font face="Calibri"> ... </font>#></font>. Typically feature control blocks contain helper functions that can be used within a standard or expression control block. In our example, we will add a method to sort the names of our friends.</p><pre class="brush: csharp;"><#+ private IEnumerable<string> SortFriends(IEnumerable<string> friends)<br /> {<br /> return (from friend in friends<br /> orderby friend ascending<br /> select friend);<br /> }<br />#></pre><br /><p>The implementation of the SortFriends method uses LINQ so we must add a new import directive for the <font face="Courier New">System.Linq</font> namespace. Further, LINQ is provided by the System.Core .NET assembly which is not referenced by default. To use LINQ, you must also add an assembly directive.</p><pre class="brush: xml;"><#@ template language="C#" #><br /><#@ assembly name="System.Core.dll" #><br /><#@ import namespace="System.Collections.Generic" #><br /><#@ import namespace="System.Linq" #><br /><#@ parameter type="IList<string>" name="friends"#><br /></pre><br /><p>To use the <font face="Courier New">SortFriends</font> method, modify the <font face="Courier New">foreach</font> statement as described below.</p><pre class="brush: csharp;"><# foreach(var friend in SortFriends(friends))</pre><br /><p>If you now run the generator with the modified T4 text template, you will get the following textual output: </p><pre>Hello World!<br /><br />Hello Mary!<br />Hello Paul!<br />Hello Peter!<br /></pre><br /><h4>Multiple parameters</h4>The <em>parameters</em> parameter of the <font face="Courier New">Generate</font> method is marked with the <a href="http://msdn.microsoft.com/en-us/library/w5zay9db.aspx" target="_blank">params</a> keyword, so you can pass a variable number of objects. You must pass these objects in the same sequence as they appear in parameter directives of the T4 text template. <br>Be aware that the parameter list is not type safe but you can create an extension method that contains exactly the parameters you need. <pre class="brush: csharp;">public static class GeneratorExtension<br />{<br /> public static void Generate(this IGenerator generator, TextWriter output, string template, IList<string> friends)<br /> {<br /> generator.Generate( template, output, friends );<br /> }<br />}</pre> Unknownnoreply@blogger.com9tag:blogger.com,1999:blog-106901210730964635.post-14945164103938868642012-06-13T15:32:00.001+02:002012-06-18T13:25:30.092+02:00Tutorial (part 1)<p>In one of my projects the customer had the requirement, that the application must be able to generate C files used in a test environment for electronic control units (ECU). I tried to generate the C code by using <a href="http://omsice.blogspot.de/2012/06/code-and-text-generation-by-using-t4.html" target="_blank">preprocessed text templates</a> integrated in Visual Studio. This worked well but the the customer had further requirements: The template for the C code had to be customizable because a change in the test environment should not necessarily lead to an modification in the application. That was the point were I decided to write my own T4 text template generator that could parse T4 text templates at run-time. Because I had other projects were I needed similar functionality, including the open source project <a href="http://sourceforge.net/projects/nhbusinessobj/" target="_blank">NHibernate.BusinessObjects</a>, I decided to make the T4 Text Template Generator available to the community.</p> <p>In the first part of this tutorial I will show you how to generate textual output by using a simple T4 text template. The examples are written in C# but you can do the same with VB. To create the T4 text templates, I use Visual Studio 2010 and the <a href="http://t4-editor.tangible-engineering.com" target="_blank">Tangible T4 Editor</a>.</p> <p>The first step is to create a T4 text template file. Therefore, create a new text file in your Visual Studio project and rename the extension to .t4. You should not create a new file based on the "Text Template” template because Visual Studio automatically assigns the <em>TextTemplatingFileGenerator</em> to the <em>CustomTool</em> property and creates a subsidiary text file. In this tutorial, you need to set the <em>Copy to Output Directory</em> attribute to either <em>Copy if newer</em> or <em>Copy always</em>.</p> <p>The template directive must be the first directive in a template file. In the language attribute specify the language (either C# or VB) used in the template. In the next line add the text you want to generate.</p><pre class="brush: xml;"><#@ template language="C#" #><br />Hello World!</pre><br /><p>The next step is to use the template in your application. Therefore, create an instance of the <font size="2" face="Courier New">OMS.Ice.T4Generator.Generator</font> class and a stream writer. On the generator call the <font size="2" face="Courier New">Generate()</font> method and pass the path to the template and a stream writer as parameters. After the T4 template has been processed, the stream writer contains the generated <em>Hello World!</em> text.</p><pre class="brush: csharp;">namespace OMS.Ice.T4Generator.Tutorial<br />{<br /> internal class Part1<br /> {<br /> public static void Generate()<br /> {<br /> IGenerator generator = new Generator();<br /> var stream = new MemoryStream();<br /> var textWriter = new StreamWriter( stream );<br /> generator.Generate( Path.Combine( AppDomain.CurrentDomain.BaseDirectory, @"Part1\Part1.t4" ), textWriter );<br /><br /> stream.Seek( 0, SeekOrigin.Begin );<br /> var textReader = new StreamReader( stream );<br /> var generatedText = textReader.ReadToEnd();<br /> }<br /> }<br />}</pre><br /><p>In the <a href="http://omsice.blogspot.de/2012/06/tutorial-part-2.html" target="_blank">second part</a> of this tutorial, I will show you how to use C# in your text template.</p> Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-106901210730964635.post-49464321991467052452012-06-06T12:15:00.001+02:002012-06-06T16:37:07.714+02:00Code and Text Generation by using T4 Text Templates<p>Using T4 text templates in the software development process is a common task. Visual Studio supports design-time code generation and run-time text generation by using preprocessed T4 text templates. However, there’s a third use case which is not supported by Visual Studio: Run-time text generation by using T4 text templates.</p> <h4>Design-Time Code Generation</h4> <p>If you need to generate code or other textual files within your Visual Studio project, you typically write a template that can be used to generate code or text from a model. If the model changes, you just need to regenerate the code.</p> <p>The design-time code generation is well integrated into the Visual Studio. For more Information see the MSDN article about <a href="http://msdn.microsoft.com/en-us/library/dd820620" target="_blank">design-time code generation</a>.</p> <h4>Run-time Text Generation by using Preprocessed T4 Text Templates</h4> <p>To generate text output at run-time, you can add a preprocessed text template to your Visual Studio project. Visual Studio automatically generates a code-behind file for the template. The generated code file contains the source code for a text generator class that can be used from your application by calling the <span><font color="#000066" size="3" face="Courier New"><font size="2">TransformText</font><font face="Calibri"> <font color="#000000">method</font></font></font></span>. Whenever you change the template, Visual Studio regenerates the subsidiary code file. For more Information see the MSDN article about <a href="http://msdn.microsoft.com/en-us/library/ee844259" target="_blank">run-time text generation</a>.</p> <p>There is a drawback by using preprocessed T4 text templates. The code for the text generator will be created at design-time. At run-time you can only pass data to the generator and the text output has a fix structure. The user cannot customize the template to his own needs.</p> <h4>Run-time Text Generation by using T4 Text Templates</h4> <p>In applications where you need customizable T4 text templates or where the user shall be able to create its own templates, you cannot use preprocessed T4 text templates. In more complex scenarios you may even have a meta template that can be used to generate different T4 text templates. There are many other use cases where you need more flexibility than given with the Visual Studio T4 text generation.</p> <p>The <a href="http://omsice.codeplex.com" target="_blank">OMS.Ice – T4 Text Template Generator</a> is all in one, a T4 text template parser, compiler and generator. At runtime, the generator parses a T4 text template, builds code in the selected language (C# or VB), compiles that code into memory, and finally executes the text generator.</p> Unknownnoreply@blogger.com0