AspAlliance.com LogoASPAlliance: Articles, reviews, and samples for .NET Developers
URL:
http://aspalliance.com/articleViewer.aspx?aId=1580&pId=-1
Creating Code Smith Templates
page
by Brian Mains
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 30960/ 57

Introduction

CodeSmith generates code the way you want it.  It uses at template that is a mix of static text and dynamic scripts to create whatever you want it to create. The dynamic scripting in CodeSmith Studio resembles both ASP scripting tags and .NET inline ASPX code. CodeSmith Studio, as depicted below, contains many samples already setup for you that you can use, and these help in creating your own custom scripts.

CodeSmith also has an online community, where hundreds of other samples reside.  Not only that, they have a forum and blogs to help with some of the questions that there may be.

This article will discuss code generation, and show some examples of creating templates that generate code the way that I wanted it to be for my processes. You will see how it can be functional to generate code the way you want it as well.

Setting up CodeSmith

To start CodeSmith, go to the CodeSmith <Version> in the programs menu, and select the CodeSmith Studio program. This application contains many similarities with Visual Studio. It supports pinnable windows, tabbed documents, a property window, and all of the other features that Visual Studio .NET developers are knowledgeable about. It builds your templates, lets you know of any errors that were found, and uses the output window to show the completed results after building successfully. Below is a snapshot of the CodeSmith studio.

Figure 1

Using this editor, the Template Explorer on the right allows you to see your own scripts and create new ones.  So what does a script look like? This article will break down a basic script for you.

CodeSmith Scripts

A script starts with a header; similar to an ASPX page, the top of the script defines the CodeTemplate header as shown below.

Listing 1

<%@ CodeTemplate Language="C#" TargetLanguage="Text" Src="" Inherits="" 
Debug="False" Description="Template description here." %>

Most of the attributes are obvious in their function; I am going to mention that templates can have code-behind files.

The script can make use of properties. Properties are not quite like code-behind properties of server controls in ASP.NET.  Instead, these properties allow the person running the script to change some of the data that the script will use.  One of my example scripts is shown in the Property Grid (as shown below).

Figure 2

The property definition is shown below. It uses a script setting with the "at" sign to note the use of a property. This property has several options that can be defined for it. Take a look at the definition below.

Listing 2

<%@ Property Name="InheritedProviderClassName" Type="String" 
Default="SomeProvider" Optional="False" Category="Class" %>

Some properties are required and some are optional, as noted by the optional attribute. A required property will cause a build error if no value is supplied. In addition, the category attribute breaks out these attributes into separate logical containers. Properties can also have a default value. The last thing I will mention is that there are various types that a property can be defined as. In most cases, it may be a string, but more specialized objects are available, as defined in the CodeSmith API. For instance, the following property uses the StringCollection object to represent a series of strings in comma-separated fashion. There is an example of this in the screenshot above, looking at the ProviderMethodNames property in the Parameters category.

Listing 3

<%@ Property Name="ProviderMethodNames" Type="StringCollection" Default="" 
Optional="False" Category="Parameters" %>

Any assemblies and imports being referenced in the script can be defined as below.

Listing 4

<%@ Assembly Name="System.Data" %>
<%@ Assembly Name="CodeSmith.CustomProperties" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Xml" %>
<%@ Import Namespace="CodeSmith.CustomProperties" %>

Again, this highlights the similarities to ASPX, where import statements define the namespaces being used.

Script Rendering

There are several ways to render the template; the first option is to place static text in the body.  Static text gets rendered as is to the final output window. The second option is to use ASP scripting tags (<% %>) in the body of the template to perform more advanced output capabilities, which I will talk about later. The third option is to define methods and variables in the following script section, similar to inline ASPX script blocks. Let us look at each option individually.

The first option is embedded static text in the script. For instance, the following can be embedded in the script.

Listing 5

Create procedure dbo.AddItem
(
  ItemKey   uniqueidentifier,
  ItemName  varchar(50)
)
As
-- Proc body

This text gets rendered to the output window as is, which is not useful. However, with scripting, it is possible to make this more functional. Let us take a look; the following is a stored procedure template I created for custom procs so that it formats it the way I want it to.

Listing 6

create procedure <%= GetTableName(true) %>_AddNew
(
<% GenerateParameters(INSERT_MODE, true, 4); %>
)
 
as
 
set nocount on
 
insert into       <%=GetTableName(true) %>
(
<% GenerateColumns(INSERT_MODE, false, 4); %>
)
values
(
<% GenerateParameters(INSERT_MODE, false, 4); %>
)
 
set nocount off
GO

The template above generates an insertion stored procedure. It uses several methods (explained later) to write content to the screen. At the top, the template gets the name of the table via the GetTableName method and embeds it into the procedure name. Next, GenerateParameters creates the list of input parameters, and the next section creates the body of the proc.

The mix of static content and dynamically generated text gives the code generation process a nicer touch; however, adding script sections makes this template even more functional. For instance, the methods below render script two different ways.

Listing 7

<script runat="template">
//Returns a string to be rendered in the script tags
public string GetTableName(bool includeOwner)
{
      return includeOwner ? string.Format("{0}.{1}"this.SourceTable.Owner, 
      this.SourceTable.Name) : this.SourceTable.Name;
}
 
//Renders the script inline using Response.Write
public void GenerateColumns(string mode, bool includeAssignments, int indent)
{
      ColumnSchemaCollection columns = this.GetColumns(mode);
      
      for (int i = 0; i < columns.Count; i++)
      {
            this.GenerateIndent(indent);
            Response.Write(this.GetColumnName(column, false));
            if (includeAssignment)
                  Response.Write(" = " + this.GetColumnName(column, true));

 

            if (i != columns.Count - 1)
                  Response.Write(",\n");
      }
      
      if (mode != UPDATE_MODE)
            Response.Write("\n");
}
</script>

In the first method (GetTableName) method, the script to render is returned as a string, which renders to the output window through the following call.

Listing 8

<%= GetTableName(true) %>

As you can see, it follows the conventions of ASP by using the <% %> tags, as well as the equals sign to render the returned string directly to the resulting output.  Note that in this usage, there is no ending semicolon.

In the second method, the output is rendered inline using another similar ASP convention:  Response.Write. A list of column objects returned by the GetColumns method are iterated through and rendered to the screen using Response.Write(). The ColumnSchema object is a specialized object in CodeSmith that represents a column in a database. These columns are rendered by outputting their name; however, if includeAssignments is set to true, it also writes a variable assignment in the form "Name = @Name" as you would see it in an update statement.

To invoke a method that does not return a string, use the statement below.  Note the use of a semicolon in this instance.

Listing 9

<% GenerateColumns(INSERT_MODE, true, 4); %>

Again, this method uses Response.Write to render the output, which works in a different way than returning a string and formatting the statement within the static text. Using Response.Write means you control the format of the text by manually inserting tabs, new lines, and other tricks.

It is possible to define constants within the template, and these constants are available both in the script tags and in the dynamic script block. In addition, variables and properties can be defined within the script section that work the same way as you would see in C#.

The CodeSmith library has a bunch of objects to make script generation easier, such as the StringCollection that takes a comma-separated list of objects and converts it to a collection, or the SchemaExplorer namespace that contains a bunch of objects that can connect to a database.  CodeSmith also uses a series of attributes to setup the design-time environment, like you see with control development in Windows or ASP.NET.

Conclusion

CodeSmith is a very functional tool. It can generate code in the form that you want it to. You can see that CodeSmith has the same conventions of C# to perform advance code generation capabilities. This article illustrated the use of the simplest mechanisms to create a template, and in future articles I will delve a little deeper into the capabilities of the tool.


Product Spotlight
Product Spotlight 

©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-05-04 5:40:34 AM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search