| Author: |
my.generation |
| Type: |
Tutorial |
| Created: |
11/17/2004 6:45:59 AM |
| Last Updated: |
11/17/2004 6:52:12 AM |
Developing DotNetScript Templates - MyGeneration
Developing DotNetScript Templates with MyGeneration
Requirements:
Overview
MyGeneration currently offers two scripting engines, the Microsoft Scripting
Engine, which provides JScript and VBScript support, and DotNetScript, which
provides VB.Net and C# support. DotNetScript is not true scripting like the
Microsoft Script Control. It actually compiles the code at runtime, then, using
reflection, executes code from the resulting compiled .net assembly. This
tutorial explains the pros and cons of developing MyGeneration templates using
DotNetScript by example. In this example, I will be using C# along with the
Nothwind SQL Server database.
Creating a new C# Template
-
Open MyGeneration.
-
Create a new template by selecting
from the menu.
-
Edit the templates properties by clicking on the properties icon
,
or by clicking on the collapsable splitter to the left of the template editor.
-
Fill in the Template Properties form (as seen below).

-
To save your work, select
from the menu. I saved the file as: C:\Program
Files\MyGeneration\Templates\DotNetScriptSample.zeus.
Examine the default template code
Default Template Body Code (C#)
Note that, unlike JScript or VBScript, C# templates are initialized with a few
lines of code. This default code is very important!!! A C# template MUST have a
class named GeneratedTemplate that extends from DotNetScriptTemplate
in the template body. MyGeneration instantiates the GeneratedTemplate class,
then invokes the Render method to begin the generation process. The
majority of template development will occur in the Render method. Try
Executing the template and view the results. You will see that the string, "Literal
content goes here", will display as the output.
<%
public class GeneratedTemplate : DotNetScriptTemplate
{
public GeneratedTemplate(ZeusContext context) : base(context) {}
public override void Render()
{
%>
Literal content goes here.
<%
}
}
%>
Default GUI Code (C#)
In the template's Interface code, there is also a class called GeneratedGui,
which inherits from DotNetScriptGui. Like the Render method in
the template body, the Setup method is the starting point for the
execution of the User Interface that collects input for the template.
public class GeneratedGui : DotNetScriptGui
{
public GeneratedGui(ZeusContext context) : base(context) {}
public override void Setup()
{
}
}
Acquiring Input: The Interface Code Block
In this example, the user needs to select a single table. This can be
accomplished in the Interface Code block. The input collected in the interface
code will be used in the template body when generating templates.
Interface Code Block using the MyGeneration API
Below is a code sample that acquires the required data from the user using the
traditional MyGeneration Gui API.
public class GeneratedGui : DotNetScriptGui
{
public GeneratedGui(ZeusContext context) : base(context) {}
public override void Setup()
{
ui.Title = ".NetScript C# Sample: Java Class";
ui.Width = 340;
ui.Height = 200;
GuiLabel label_d = ui.AddLabel("lblDatabases", "Select a database:", "Select a database in the dropdown below.");
GuiComboBox cmbDatabases = ui.AddComboBox("databaseName", "Select a database.");
GuiLabel label_t = ui.AddLabel("lblTables", "Select table:", "Select table from the combobox below.");
GuiComboBox cmbTables = ui.AddComboBox("tableName", "Select a table.");
cmbDatabases.BindData(MyMeta.Databases);
cmbDatabases.SelectedValue = MyMeta.DefaultDatabase.Name;
cmbTables.BindData( MyMeta.Databases[cmbDatabases.SelectedValue].Tables );
cmbDatabases.AttachEvent("onchange", "cmbDatabases_onchange");
ui.ShowGui = true;
}
public void cmbDatabases_onchange(GuiComboBox control)
{
GuiComboBox cmbDatabases = ui["databaseName"] as GuiComboBox;
GuiComboBox cmbTables = ui["tableName"] as GuiComboBox;
cmbTables.BindData( MyMeta.Databases[cmbDatabases.SelectedValue].Tables );
}
}
Interface Code Block using the .Net Windows Forms API (C#)
Below is an example of a different approach of acquiring the same data without
using the MyGeneration GUI API. You'll quickly notice that the code below is
just plain old C# Windows Forms code. At the top, there are a special
directives that allow the developer to reference assemblies and import
namespaces.
<%#REFERENCE System.Windows.Forms.dll %>
<%#NAMESPACE System.Windows.Forms %>
public class GeneratedGui : DotNetScriptGui
{
public GeneratedGui(ZeusContext context) : base(context) {}
public override void Setup()
{
AcquireInputForm form = new AcquireInputForm(MyMeta, input);
if (form.ShowDialog() != DialogResult.OK)
{
ui.IsCanceled = true;
}
}
}
public class AcquireInputForm : Form
{
private ComboBox cboDatabases = new ComboBox();
private ComboBox cboTables = new ComboBox();
private Button btnOk = new Button();
private dbRoot meta;
private IZeusInput input;
public AcquireInputForm(dbRoot mymeta, IZeusInput zin)
{
this.meta = mymeta;
this.input = zin;
this.BindComboBox(cboDatabases, meta.Databases);
cboDatabases.SelectedItem = meta.DefaultDatabase.Name;
cboDatabases.Top = 10; cboDatabases.Left = 10; cboDatabases.Width = 200;
cboDatabases.SelectedIndexChanged += new EventHandler(cboDatabases_SelectedIndexChanged);
this.BindComboBox(cboTables, meta.DefaultDatabase.Tables);
cboTables.Top = 50; cboTables.Left = 10; cboTables.Width = 200;
btnOk.Text = "Ok";
btnOk.Top = 100; btnOk.Left = 10; btnOk.Width = 200;
btnOk.Click += new EventHandler(btnOk_Click);
this.Controls.AddRange( new Control[] {cboDatabases, cboTables, btnOk} );
this.Text = ".NetScript C# Sample: Java Class";
this.Width = 230;
this.Height = 160;
}
public void cboDatabases_SelectedIndexChanged(object sender, EventArgs args)
{
this.BindComboBox(
cboTables,
meta.Databases[ cboDatabases.SelectedItem.ToString() ].Tables
);
}
public void btnOk_Click(object sender, EventArgs args)
{
if ((cboDatabases.SelectedIndex >= 0) &&
(cboTables.SelectedIndex >= 0))
{
input["databaseName"] = cboDatabases.SelectedItem.ToString();
input["tableName"] = cboTables.SelectedItem.ToString();
this.DialogResult = DialogResult.OK;
this.Close();
}
else
{
MessageBox.Show("Fill out the required fields.. PLEASE??");
}
}
private void BindComboBox(ComboBox cbo, IEnumerable myMetaCollection)
{
cbo.Items.Clear();
foreach (INameValueItem item in myMetaCollection)
{
cbo.Items.Add(item.ItemValue);
}
}
}
The Template Body
The template body code block is where the code generation is actually performed.
Below is a step by step walkthrough of how I go about developing templates.
Step 1: Paste desired output into the body of the Render method
Inside the code sample below, you'll see the the target class I'm looking to
generate. This is almost always the first thing I do when I'm starting a new
template.
<%
public class GeneratedTemplate : DotNetScriptTemplate
{
public GeneratedTemplate(ZeusContext context) : base(context) {}
public override void Render()
{
string databaseName = input["databaseName"].ToString();
string tableName = input["tableName"].ToString();
%>
package com.mygeneration.sample;
import java.sql.*;
import com.mygeneration.businessobjects.*;
import com.mygeneration.dataaccess.*;
public class Employee extends BizObj
{
public Employee()
{
}
public String getEmployeeID()
{
return getString(EmployeeSchema.EmployeeID.getFieldName());
}
public void setEmployeeID(String employeeID)
{
setString(EmployeeSchema.EmployeeID.getFieldName(), employeeID);
}
}<%
}
}
%>
Step 2: Add dynamic code
Add the dynamic code to the template body that replaces the class name, property
names, and data types.
<%
public class GeneratedTemplate : DotNetScriptTemplate
{
public GeneratedTemplate(ZeusContext context) : base(context) {}
public override void Render()
{
string databaseName = input["databaseName"].ToString();
string tableName = input["tableName"].ToString();
IDatabase database = MyMeta.Databases[databaseName];
ITable table = database.Tables[tableName];
%>
package com.mygeneration.sample;
import java.sql.*;
import com.mygeneration.businessobjects.*;
import com.mygeneration.dataaccess.*;
public class <%= table.Alias %> extends BizObj
{
public <%= table.Alias %>()
{
}
<%
foreach (IColumn column in table.Columns)
{
string datatype = this.GetJavaType(column);
%>
public <%= datatype %> get<%= column.Alias %>()
{
return get<%= datatype %>(<%= table.Alias %>Schema.<%= column.Alias %>.getFieldName());
}
public void set<%= column.Alias %>(<%= datatype %> m_<%= column.Alias %>)
{
set<%= datatype %>(<%= table.Alias %>Schema.<%= column.Alias %>.getFieldName(), m_<%= column.Alias %>);
}
<%
}
%>
}<%
}
private string GetJavaType(IColumn column)
{
string sqlServerType = column.DataTypeName;
int charLength = column.CharacterMaxLength;
switch (sqlServerType)
{
case "bit":
return "Boolean";
case "decimal":
case "float":
case "numeric":
case "money":
case "smallmoney":
case "real":
return "Decimal";
case "tinyint":
case "smallint":
case "int":
case "bigint":
return "Integer";
case "smalldatetime":
case "datetime":
return "Timestamp";
case "varchar":
case "char":
case "nvarchar":
case "nchar":
case "text":
if (charLength == 1)
return "Character";
else
return "String";
default:
return "Object";
}
}
}
%>
Conclusion
Using DotNetScript, you can take MyGeneration template development to a new
level of power and complexity. While dealing with stongly typed classes may be
cumbersome compared to variants in VBScript and JScript, DotNetScript provides
easy access to all the wonders of the .net framework class library. Keep your
eyes open for more related tutorials in the near future.
Justin Greenwood
MyGeneration Software
http://www.mygenerationsoftware.com/
October 7, 2004
|