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

Introduction

In two previous articles, I wrote an introduction for CodeSmith that illustrated how to setup a template, along with another article using the SchemaExplorer assembly.  For the last article in the series, I want to display a couple of useful templates that may help you when you develop your own custom templates, or at least understand more about CodeSmith in general.

You probably know of something that you type over and over again, and even though there are similarities with other pieces of code you write, it is not quite the same. Coding it fresh is usually the best option.  Because of this, added time to development cycles occurs.

Enter CodeSmith tools. This suite of tools generates code for you the way that you want it to appear; all that is required is to write the template (it does not have templates that generate templates, that would be chaos).  Let us look at some examples.

Generating Web Control Properties

ASP.NET custom controls work with a ViewState dictionary, which stores the values of its inner properties referenced by a key. The data resides on the server so the values can be retained across postbacks, since the web is a stateless environment.  The following is an example property for a custom control.

Listing 1

public int TotalRecords
{
  get
  {
    object o = ViewState["TotalRecords"];
    return (o == null) ? 0 : (int)o;
  }
  set
  {
    ViewState["TotalRecords"= value;
  }
}

As you can see in the script, there are two main dynamic components involved: the property name and its data type. The rest of the code is very similar in use (with the exception of the default value returned; we will get to that in a moment).  The following script helps reduce the effort by using a name/value collection that contains the data types/property names to use. In this script, the name is the data type for the property and the value is the property name. What is nice about this approach is that the CodeSmith studio uses a friendly editor to enter the values into the system.

The property type and name values are used to generate a list of getters and setters. It does not provide a mechanism to create read-only properties, mainly because it is simple enough to delete the setter from the generated code. It also does not worry about defining the custom control class because that is usually pretty specialized. Instead, I create the class and use the template to generate the property definitions.

This script makes use of some of the CodeSmith objects defined in the following assembly.

Listing 2

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

It also defines a name/value collection which has a built-in editor described above.

Listing 3

<%@ Property Name="PropertyTypesNames" Type="NameValueCollection" Optional="False" 
  Editor="CodeSmith.CustomProperties.NameValueCollectionEditor,
  CodeSmith.CustomProperties" %>

The Editor attribute applies the name/value property editor; when selecting the PropertyTypesNames property in the properties window, the ellipsis button appears allowing the user to invoke the design-time editor. Take a look at the editor below.

Figure 1

Using the above properties, the script takes these values and converts them to properties as such:

Listing 4

<%
for (int i = 0; i < this.PropertyTypesNames.Count; i++)
{
      string dataType = this.PropertyTypesNames[i].Key;
      string name = this.PropertyTypesNames[i].Value;
      %>
            public <%= dataType %> <%= name %>
            {
                  get
                  {
                        object o = ViewState["<%= name %>"];
                        return (o == null) ? 
                                        <%= GetDefaultDataTypeValue(dataType) %> : 
                                        (<%= dataType %>)o;
                  }
                  set { ViewState["<%= name %>"= value; }
            }
            
      <%
}
%>

The script above is pretty simplistic. First, it gets a local reference to the data type and name.  It uses these to embed the values into the public property definition using the <%= %> notation, which you may be familiar with if you have done ASP scripting. It loops through, using the name as the viewstate key, and creates a replica property as shown previously. You may wonder what GetDefaultDataTypeValue does; this method simply returns a default value for the data type provided, which does a little conversion for simple types (returning zero for numeric types as the default value, Guid.Empty for guid values, etc.).  The following script renders:

Listing 5

public bool IsApproved
{
  get
  {
    return ViewState["IsApproved "] ?  ? false;
  }
  set
  {
    ViewState["IsApproved"= value;
  }
}
 
public string Text
{
  get
  {
    return ViewState["Text"] ?  ? string.Empty;
  }
  set
  {
    ViewState["Text"= value;
  }
}
 
public string Value
{
  get
  {
    return ViewState["Value"] ?  ? string.Empty;
  }
  set
  {
    ViewState["Value"= value;
  }
}

You may wonder why we do not include the class name; usually, web control classes are complicated with the inheritance structures they use, so this skips that part, simply meant to copy the properties into the file.

Generating Configuration Section Properties

Configuration sections add to the usefulness of an application, whether it is a web or windows application, or even a custom library of components. Configuration sections are portions of the configuration file that represent specific settings for the application that it represents. I am not going to go into too much detail regarding them; for more information, please consult the following article.

The syntax for declaring properties of a custom configuration section, or a configuration element, can be tedious. Look at the following example.

Listing 6

[ConfigurationProperty("redirectUrl", DefaultValue = "default.aspx")]
public string RedirectUrl
{
  get
  {
    return (string)this["redirectUrl"];
  }
  set
  {
    this["redirectUrl"= value;
  }
}

The above example is a property of a configuration section. To expose the property, the ConfigurationProperty attribute declares the name that will appear as an attribute, along with additional criteria (in this example, a default value to use when a value is not provided).

In addition, configuration sections use a collection of properties, which have a type of object.  Casting the value to the appropriate type is a requirement. It is not difficult to do, but there is a way to make it easier. To start, the script uses two properties to define the namespace and name of the class.

Listing 7

<%@ Property Name="ClassName" Type="String" Default="" Optional="False" %>
<%@ Property Name="ClassNamespace" Type="String" Default="Nucleo.Configuration" 
   Optional="False" %>

This approach uses an XML file as the source to illustrate another approach for storing data.  Rather than hard-coding the file name, I chose to use the FileNameEditor, which is a file-browsing editor that allows me to navigate to a file in a graphical window. This object resides in the System.Windows.Forms assembly. The definition to use this approach is shown below.

Listing 8

<%@ Property Name="ConfigurationFile" Type="String" Default="" Optional="False" 
    Editor="System.Windows.Forms.Design.FileNameEditor, System.Design, 
    Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" %>

To add file selection editing capabilities, one simply needs to reference the Design assembly using the full name. These properties store what we are calling the object,and where to get the data.  What does the data look like? Below is a single entry in the XML file.

Listing 9

<Property>
      <Type>bool</Type>
      <Name>UseThat</Name>
      <IsRequired>true</IsRequired>
</Property>

This property element is wrapped by a parent element, and mimics the structure that a dataset uses to read/write XML. Note the three properties: type (of data), name, and whether the field is required.  All of this will affect the output. The script gets the data by reading the XML into a DataSet object and assigning the table locally.

Listing 10

private void ReadFile()
{
  DataSet propertiesData = new DataSet();
  propertiesData.ReadXml(this.ConfigurationFile);
  _propertiesTable = propertiesData.Tables[0];
}

This method is triggered to run at the beginning of the script. Following the download of the data, the script continues by rendering the base shell.

Listing 11

using System;
using System.Configuration;
namespace <%= this.ClassNamespace %>
{
      public class <%= this.ClassName %> : ConfigurationSection
      {
      }
}

Next, each of the properties renders using information from the DataTable object that holds all the property data. It is read from as shown below.

Listing 12

<%
foreach (DataRow row in _propertiesTable.Rows)
{
      string propertyType = row["Type"].ToString();
      string propertyName = row["Name"].ToString();
      bool isRequired = bool.Parse(row["IsRequired"].ToString());
%>
      [ConfigurationProperty(<%= this.GetConfigurationName(propertyName) %>, 
         IsRequired=<%= isRequired.ToString() %>)]
      public <%= propertyType %> <%= propertyName %>
      {
            get
            { 
                  return (<%= propertyType %>)
                    this["<%= this.GetConfigurationName(propertyName) %>"];
            }
            set { this["<%= this.GetConfigurationName(propertyName) %>"= value; }
      }
<%
}
%>

Note the <% %> tags; this is the server-side scripting portion that sets up a for loop to access through each of the properties, gets a local variable reference, appends the ConfigurationProperty attribute, declares the getter and setter, and makes sure all the assignments are correct. Also note that the GetConfigurationName method simply converts the first letter of the word to lower case.

This is a pretty simple script that renders the following.

Listing 13

using System;
using System.Configuration;
namespace Nucleo.Configuration
{
  public class SomeSection: ConfigurationSection
  {
    [ConfigurationProperty(useThat, IsRequired = True)]
    public bool UseThat
    {
      get
      {
        return (bool)this["useThat"];
      }
      set
      {
        this["useThat"= value;
      }
    }
    [ConfigurationProperty(useThis, IsRequired = False)]
    public bool UseThis
    {
      get
      {
        return (bool)this["useThis"];
      }
      set
      {
        this["useThis"= value;
      }
    }
  }
}

Though not complicated to setup manually, this template helps create longer configuration sections rather easily. I have had configuration sections that this was useful for.

Generating AJAX Client Control Classes

If you have read into the ASP.NET AJAX framework and the AJAX Control Toolkit, you know that Microsoft built into the ASP.NET AJAX framework a client library of components that make developing AJAX controls and extenders easier. The script, for the most part, follows a common makeup, and this basic makeup can be easily generated via CodeSmith. This script requires more explanation, so bear with me on it.

The JavaScript structure is expressed in a specific way. At the beginning is the creation of the namespace. The next section is the creation of the class, with a constructor, properties, methods, and event handlers. Following this is the event handlers that tap into the base DOM element events. Last is the definition of the prototype, descriptor, and the registration of the class.

If you are not familiar with this model of writing JavaScript and are not sure what I mean, you may want to read a few other articles on the subject. I have attached a couple for you to understand the base structure.

http://www.asp.net/ajax/documentation/live/tutorials/EnhancingJavaScriptTutorial.aspx

http://www.asp.net/AJAX/Documentation/Live/tutorials/ExtenderControlTutorial1.aspx

http://www.asp.net/AJAX/Documentation/Live/tutorials/IScriptControlTutorial1.aspx

To begin, my script contains the following properties:

·         ObjectNamespace - The namespace of the object. The ASP.NET AJAX framework mimics ASP.NET framework by including namespace registration.

·         ObjectName - The name of the class.

·         InheritedObjectName - The name of the base class that the JavaScript inherits from. Some of the options are Sys.UI.Component, Sys.UI.Control, Sys.UI.Behavior, and other classes that you derive.

·         Properties - A string collection that contains the properties that the AJAX class exposes. Both getters and setters are exposed.

·         ExposedEvents - A string collection of events that the class exposes; events can be raised from the JavaScript class.

·         EventsListenedTo - The JavaScript class taps into the events of the DOM element that it extends. For instance, a text element has key and mouse events that are raised, which the JavaScript class can listen to. These are the events that the class taps into.

I am going to skip the namespace registration and head right into the constructor. The following is the definition of the constructor in the script.

Listing 14

<%= this.GetAjaxClassName(false) %> = 
function <%= this.GetAjaxClassName(true) %>(associatedElement)
{
      <%= this.GetAjaxClassName(false)%>.initializeBase(associatedElement);
      
<%
foreach (string property in this.Properties)
{
%>
      this.<%= this.GetVariableName(property) %> = null;
<%
}
%>
 
<%
foreach (string listenedEvent in this.EventsListenedTo)
{
%>
      this.<%= this.GetHandler(listenedEvent) %> = null;
<%
}
%>
}

The constructor script defines both variable names for the properties and event handlers for the DOM events. The definitions render in the constructor here; to create the correct name, the following helper methods alter the original values as necessary.

Listing 15

public string GetHandler(string eventName)
{
  return "_" + eventName.Substring(0, 1).ToLower() + eventName.Substring(1) + "Handler";  
}
 
public string GetVariableName(string propertyName)
{
  return "_" + propertyName.Substring(0, 1).ToLower() + propertyName.Substring(1);
}

Any properties are defined in the list output next. If there are no properties, the script handles this correctly and leaves an empty space.

Listing 16

<%
foreach (string property in this.Properties)
{
%>
function <%= this.GetAjaxClassName(true) %>$get_<%= property %>()
{
      return <%= this.GetVariableName(property) %>;
}
 
function <%= this.GetAjaxClassName(true) %>$set_<%= property %>(value)
{
      <%= this.GetVariableName(property) %> = value;
}
 
<%
}
%>

The above method renders a series of setters and getters in the form of:

Namespace$Namespace2$get_PropertyName. You may wonder why the "$" for the property name; this is a way to create a unique function as the getter and setter. There are a couple of approaches to creating the AJAX interface, where this one assigns a shorter name in the prototype definition. For instance, the property name above would have the following entry in the prototype definition.

Listing 17

get_PropertyName : Namespace$Namespace2$get_PropertyName

The following is the rendering of the prototype.

Listing 18

<%= this.GetAjaxClassName(false) %>.prototype = 
{
<%
foreach (string property in this.Properties)
{
%>
    get_<%= property %> : <%= this.GetAjaxClassName(true) %>$get_<%= property %>,
    set_<%= property %> : <%= this.GetAjaxClassName(true) %>$set_<%= property %>,
<%
}
 
foreach (string listenedEvent in this.EventsListenedTo)
{
%>
    <%= listenedEvent %>Callback : <%= this.GetCallbackName(listenedEvent) %>,
<%
}
 
foreach (string exposedEvent in this.ExposedEvents)
{
%>
    add_<%= exposedEvent %> : <%= this.GetAjaxClassName(true) %>$add_<%= exposedEvent %>,
    raise_<%= exposedEvent %> : <%= this.GetAjaxClassName(true) %>$raise_<%= exposedEvent %>,
    remove_<%= exposedEvent %> : <%= this.GetAjaxClassName(true) %>$remove_<%= exposedEvent %>,
<%
}
%>
    initialize : <%= this.GetAjaxClassName(true) %>$initialize,
    dispose : <%= this.GetAjaxClassName(true) %>$dispose
}

This simply renders the short name to long name mappings as I mentioned above. It probably does not make a lot of sense unless you have some ASP.NET AJAX experience, especially since I did not cover every section.

References
Conclusion

I have illustrated the use of using CodeSmith to create some useful scripts. I have included the scripts in a zip file for you to download, as well as a sample output. I am still developing some of the scripts, but as they become more advanced, they become more useful. You can download these samples here.



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