Introduction
The purpose of this article is to provide a look "under the hood" of RapTier Active Templates and show some examples that you can use as a start point for your own templates. If you are familiar with the fundamentals of ASP.NET or JSP, you will be surprised how little you need to learn to start creating your own code generation templates that utilize all the power of .NET framework and flexibility of C#.
Background
Prerequisites
- .NET framework 1.0 or 1.1. Please follow this link "How to get the .NET Framework" to download the .NET framework.
- RapTier. If you don't have RapTier installed, please download it here. (Free edition available).
What RapTier is
RapTier is a template-based C#, VB.NET and SQL Code Generator that allows developing powerful and robust database-driven .NET applications in minutes.
Unlike many other code generation tools that use "passive" templates with a limited set of tags replaced during generation, RapTier utilizes Active Templates (AT) technology. An Active Template is a mixture of static code and C# instructions that control the way the code is generated. By using/modifying existing or creating new templates, you are able to generate code that meets your specific development requirements.
Every time before RapTier generates code, Active Template Engine (ATE) checks whether any template file (the file with the atcs extension) in the selected template group was updated since the last compilation. If it finds a modified template file, ATE converts all the group templates into C# classes, which inherit the TwoLKit.Ate.TextFileGenerator
abstract class, and compiles them into a .NET assembly.
After the assembly is compiled, ATE loads it, creates the new instances of the necessary template classes and calls the Generate
method created by the ATE from the template code.
Active Template Syntax
A template file contains any combination of the following elements:
- Base output code (C#, VB.NET, Java, HTML, ASP.NET, SQL, etc.)
- Code blocks
- Named code blocks
- Comments
Code Blocks
Code blocks are used to define inline code or inline expressions that execute when the template is processed. Use inline code to define code blocks or control flow blocks. Use inline expressions as a shortcut for calling the Writer.Write
method.
Script Block |
Description |
<# code #> |
Defines one or more lines of code that executes when the template is processed. |
<# code ##> |
Defines one or more lines of code that executes when the template is processed. Ignores all white space characters (including the EndOfLine symbol) starting from the ending tag ##> till either the end of line or any non-white space symbol. |
<#= expression #> |
Shortcut for <# Writer.Write(expression); #> |
<#= expression ##> |
Shortcut for <# Writer.Write(expression); ##> |
Named Code Blocks
The general format for named blocks is <#@ BlockName BlockSpecificData #>
or <#@ BlockName BlockSpecificData ##>
. The second format is used to ignore all white space characters (including the EndOfLine symbol) starting from the ending tag ##>
till either the end of line or any non-white space symbol.
Currently the template engine supports two types of named blocks: Imports
and InstanceMembers
.
The @Imports
block is used to import namespaces and, hence, allow C# template code to utilize .NET classes without specifying the full class names. The @InstanceMembers
code block includes template methods and properties. It must at least implement the RelativeFilePath
property that is declared in the abstract TwoLKit.Ate.TextFileGenerator
class. This property specifies the name and the relative location of the output file.
Comments
Comments are normally used to annotate code for future reference or make a part of the template inactive. The template engine does not process anything within the opening and closing comment tags.
Script Block |
Description |
<#-- commented out code or content --#> |
Makes a part of a template inactive. |
<#-- commented out code or content --##> |
Makes a part of a template inactive. Ignores all white space characters (including the EndOfLine symbol) starting from the ending tag ##> till either the end of line or any non-white space symbol. |
Note: You can find more information about the Active Template syntax in the RapTier documentation.
Although syntax of all Active Templates is the same, RapTier distinguishes 5 different types of templates using the template file name.
- Database_XYZ.atcs - Invoked once receiving
IDatabase
in the Database
environment variable.
- Table_XYZ.atcs - Invoked one time for every table in the database model. When calling this method, RapTier passes
ITable
as the Table
environment variable.
- Procedure_XYZ.atcs - Invoked one time for every stored procedure or function in the database model. When calling this method, RapTier passes
IStoredProcedure
as the Procedure
environment variable. (since RapTier 1.4)
- DirectoryInfo.atcs - Used to control the code generation of all templates in the directory (and all the sub-directories) where DirectoryInfo.atcs is located.
- XYZ.atcs - RapTier doesn't call this type of templates directly. They are used to store shared static methods and properties used by other templates.
Sample Template
After you have learned the theoretic basics of Active Templates, we will move to the practical part. Let�s create a template that would generate a simple HTML documentation for database schemas.
To create a new template, open the <RapTierRootDirectory>/Templates directory and create a new directory for your template group, for example SimpleDbDoc. After that, create the Template.config file.
The file structure must look like this:
Next open Template.config and copy the code below in it.
="1.0"
<TemplateConfig>
<Id>RapTierTutorial.SimpleDbDoc</Id>
<Name>Simple DbDoc Template</Name>
<Description>Simple DB documentator.</Description>
<References>
<Reference>TwoLKit.Ate.dll</Reference>
<Reference>TwoLKit.nTierBuilder.Api.dll</Reference>
</References>
</TemplateConfig>
Where:
Id
- unique template ID
Name
- template display name
Description
- optional template description
References
- a list of the "non-standard" .NET assemblies used by the template script.
Usually Template.config file include only two references TwoLKit.Ate.dll and TwoLKit.nTierBuilder.Api.dll. These references are used by the template engine to compile the template files to a .NET assembly.
Now let's create our first template. The template in this example will generate the Default.htm file that displays a list of links to HTML pages with basic table information.
First, we will create a text file named Database_Default.atcs, and enter the code below in it. You can use the source code provided with this article.
Database_Default.atcs
<html>
<head>
<title><#= Database.CodeName #></title>
</head>
<body>
<h4><#= Database.CodeName #></h4>
<ul>
<# // Iterates through the collection of the table columns
foreach(ITable table in Database.Tables)
{ ##>
<li><ahref="<#= table.Name#>.htm"><#=
table.Name #></a></li>
<# } ##>
</ul>
</body>
</html>
<#--
The code below imports namespaces and
declares methods and properties that are
used by the template only. This code will
not be copied into the output file.
--##>
<#@ Imports
using System;
using TwoLKit.nTierBuilder.Api.DbDom;
/* We need to import this namespace for IDatabase,
ITable and other DB DOM interfaces */
##>
<#@ InstanceMembers
// Every template must override the RelativeFilePath
// property to return the name of the output file
public override string RelativeFilePath
{
get { return "Default.htm"; }
}
// We don't have to create this property,
// however it simplifies the template code
// and allows i.e. using <#= Database.CodeName #>
// instead of <#=
//((IDatabase)Environment["Database"]).CodeName #>
private IDatabase Database
{
// RapTier sends IDatabase as the
// Database environment variable
get { return (IDatabase)Environment["Database"]; }
}
##>
As you can see, the top part of the code is a mixture of the base output text (in our case this is HTML) and C# code. After that we added an optional comment block. And then two code blocks @Imports
and @InstanceMembers
.
Second, we need to create a template for generating HTML pages that display table and view details. Create a file and name it Table_TableInfo.atcs. After that, enter the code below and save the changes.
Table_TableInfo.atcs
<html>
<head>
<title><#= Table.Name #></title>
</head>
<body>
<h4><#= Table.Name #> Columns</h4>
<ul>
<# foreach(IColumn column in Table.Columns)
{ ##>
<li><#= column.Name #> (<#= column.DbType #>)</li>
<# } ##>
</ul>
</body>
</html>
<#--
The code below imports namespaces and
declares methods and properties that are
used by the template only. This code will
not be copied into the output file.
--##>
<#@ Imports
using System;
using TwoLKit.nTierBuilder.Api.DbDom;
/* We need to import this namespace for
IDatabase, ITable and other DB DOM interfaces */
##>
<#@ InstanceMembers
// Every template must override the RelativeFilePath
// property to return the name of the output file
public override string RelativeFilePath
{
// Dynamically create the name of the output file
get { return Table.Name + ".htm"; }
}
// We don't have to create this property,
// however it simplifies the template code
// and allows i.e. using <#= Database.CodeName #> instead of
// <#= ((IDatabase)Environment["Database"]).CodeName #>
private ITable Table
{
get { return (ITable)Environment["Table"]; }
}
##>
Now you are ready to test your first RapTier template. Simply run RapTier, connect to a database (supported databases: MS SQL Server, MSDE, MS Access, Oracle, MySQL), in the Template Group combo-box, select the SimpleDbDoc template item, and choose the Generate Code menu item from the Project menu.
After the successful generation, open the generated project in Internet Explorer. You've just created your first RapTier template and generated a database-driven application!
Advanced Template Features
- Enabled Property
The Enabled
property controls whether the template is enabled. The default value is true
.
- RewriteExistingFile Property
The RewriteExistingFile
property is declared in the TwoLKit.Ate.TextFileGenerator
and used to control whether RapTier rewrites the output file if the file already exists. This property can be overwritten in the template. The default value is true
.
- Database object extended properties
RapTier 1.x templates receive the majority of the code generation settings through the extended properties of the IDatabase
interface.
RapTier supports the following IDatabase
extended properties:
- TargetIDEProperty - The target IDE code. Has one of the following values:
VSNET2002
, VSNET2003
, BDS
.
- DbEngine - The database engine name. Has one of the following values:
Generic
, MSSQL
, Access
, Oracle
, MySql
.
- BaseOutputDirectory - The base output directory path.
- DbTierNamespace - The base namespace for all DB-tier classes.
- WinUITierNamespace - The base namespace for all WinForm UI classes. (since RapTier 1.4)
- WebUITierNamespace - The base namespace for all WebForm UI classes. (since RapTier 1.4)
- GenerateWinUI - Specifies whether the WinForm UI code will be generated.
- GenerateWebUI - Specifies whether the WebForm UI code will be generated. (since RapTier 1.4)
- GenerateStoredProcedures - Specifies whether the stored procedures will be generated. (since RapTier 1.4)
- GenerateSqlIdentity - Specifies whether the
IDENTITY
columns are supported. (since RapTier 1.4)
- Copyright - Copyright text.
- Passing data among templates
In some cases, it is necessary to share data among several templates. To accomplish this, you can utilize the Session variables ( Environment.Session[<KeyName>]
).
RapTier processes the templates in the following order:
- DirectoryInfo.atcs template
- Database_Xyz.atcs template(s)
- Table_Xyz.atcs template(s)
- Procedure_Xyz.atcs template(s)
- Templates in the child directories
- DirectoryInfo
DirectoryInfo
templates don't generate any code. These template files are used to control whether RapTier processes other template files located in the same directory and all sub-directories. RapTier checks the DirectoryInfo
Enabled
property before processing any other templates. If this property returns true
, RapTier gets the RelativeFilePath
property value to create the base output directory for all other templates.
Conclusion
In this article, we examined the structure of RapTier templates. The ASP.NET-like syntax used in the templates allows to grasp and apply the technique very quickly. All templates provided with RapTier can be used "as is" or extended and customized to fit your standards and requirements.
For the purpose of this article, I tried to keep the logic of the "SimpleDbDoc" template, simple. Feel free to extend the template further, or check out "DbDoc" - a template that generates a complete database documentation in HTML format.
Happy programming!