Smart Code Generator .Net - Code Generation experience with Visual Studio and ASP.NET- Architectural Overview.






4.30/5 (14 votes)
Jan 7, 2007
16 min read

103024

1507
This article describes how I coupled Visual Studio and ASP.NET and created a very powerful code generator. Also describes the internals of SmartCodeGenerator and how it is possible to extend the framework to meet your needs. SmartCodeGenerator uses cutting edge technologies that are available today.
Background
I was playing with code generation tools and came across Code Smith which seemed very promising and uses an ASP.NET host engine to parse and generate output. I started studying more on ASP.NET and the ASP.NET Host Engine and realized that all that is done in Code Smith can be done via plain ASP.NET and Visual Studio. As a result, I invented SmartCodeGenerator. The large majority of this research was done about a year ago, however, I got busy with Pageflakes and other projects and did not get a chance to publish any of my work. Anyway, finally I arranged some time and published SmartCodeGenerator (SCG) at Codeplex.
For the latest source code and updates please refer to Codeplex. This article is based on CTP2.5 and is more of an architectural overview of SCG. To get familiar on how to use SCG to generate text based output, please refer to the tutorials at SmartCodeGenerator Quick start v2.0 and check this Article at Code Project "SmartCodeGenerator - Code Generation experience with Visual Studio and ASP.NET- Usage Overview". For the user forum which allows the sharing of SCG-based resources and ideas, please refer to SmartCodeGenerator Community Site.
Introduction
SmartCodeGenerator (SCG) is an ASP.NET 2.0 website or an ASP.NET 1.1 web application and is a fully-fledged template-based code generator that allows you to generate code for any text language. Templates are written in Visual Studio as ASP.NET User Controls. The code generation process can be customized by using properties.
The current feature list of SmartCodeGenerator includes:
- All development done in VS2005 or VS2003
- Extensible Template Generation Engine
- MS SQL Server, MySQL & Oracle Database schema discovery API
- Uses existing ASP.NET 2.0 website application or ASP.NET 1.1 web application concepts
- Generates text based output
- Generates output in batch mode
- Fully customizable template-based code generation
- Intellisense, compilation, debug, code snippet, sourceview, designview and all other countless cool features that are offered by Visual Studio.
The entire development life cycle of creating custom templates using SmartCodeGenerator is done using Visual Studio by creating an ASP.NET application. So during the generation of templates, intellisense, compilation, debug, source view, design view, codebehind file and all other features of Visual Studio (2005 or 2003) are available to you.
SCG supports custom properties, and any properties that are defined in the TheProperties
class are automatically picked up by the SCG Framework and a relevant UI is generated to collect data from an end user. You can define any .NET Object Type as properties of the TheProperties
class in the SCG project. Each property type in the TheProperties
class is then mapped to a UIProperty
object. At this stage it supports common types such as string, int, boolean, enum, StringCollection, and ScTableSchema type (which represents any database table schema). However, the SmartCodeGenerator Framework is extensible and UIProperty
objects for any .NET types and DBSchemaProviders
for any database source can be easily written.
SmartCodeGenerator Terms and Verbs
While reading the introduction, you came across terms such as Property Type, TheProperties
Class, Template, UIProperty
, DBSchemaProvider
etc., and you might be wondering what these are. So, let's clarify them first and then we will explore the architecture and framework of SCG.
- SmartCodeGenerator Project: is simply an ASP.NET 2.0 website project or an ASP.NET1.1 WebApplication.
- SmartCodeGenerator Template: is ASP.NET User Control.
- Property Type: Any .NET Type. Examples include: string, boolean, int, or any Custom Object like Customer, Employee etc.
TheProperties
Class: is simply a .NET class and any properties that are defined in this class are automatically picked up by the SCG Framework and a relevant UI is generated to collect data from an end user. For example, I have defined a string property TestProperty
.
public class TheProperties
{
private string _testProperty;
public string TestProperty
{
get
{
return _testProperty;
}
set
{
_testProperty = value;
}
}
}
And the SCG Framework will automatically generate a UI for this property like this.
Fig: Custom Property UI
SmartCodeGenerator UIProperty: is ASP.NET User Control. The UIProperty
objects are custom User Interface objects which are created based on the property types of the TheProperties
class. As UIProperty
objects are ASP.NET User Controls they are very easy to write.
So you should have already noticed there is no need to learn any new technologies. Code is written as you would normally write code for an ASP.NET application.
SmartCodeGenerator Framework
I will discuss the SCG Framework from 2 different perspectives. Firstly, I will discuss the SCG workflow.
Secondly, I will discuss SCG Framework's heart and soul SCPageBase
and SCEventArgs
, and also how SCGPageBase
Events are categorized to create 2 different pipelines and how SCEventArgs
are passed in the pipeline.
LoadUIProperty Pipeline:
OnPreLoadUIProperties
: Called beforeUIProperty
is generated.OnLoadUIProperties
: Called duringUIProperty
generation.OnLoadUIPropertiesComplete
: Called afterUIProperty
generation
Generate (Output) Pipeline:
OnPreGenerate
: Called before generating output.OnGenerate
: Called during output generation.OnGenerateComplete
: Called after output generation is complete.OnCleanTheProperties
: A final event to allow cleaning.
Based on responsibility, the SmartCodeGenerator Framework can be divided into four sections.
- Identify Custom Properties
- Generate UI for Custom Properties
- Identify Templates and Output Path
- Generate Output.
Identify Custom Properties
I have seen custom properties offered in Code Smith and it's a very handy concept where an end user can enter values for the custom properties and code is generated accordingly. In Code Smith we declare custom properties using tags like this
<%@ Property Name="MSN" Optional="True" Type="System.String" Category=
"General" Default="shahed.khan@gmail.com" Description="Email Address" %>
Declaring this as a tag is very cumbersome and I was not very happy with this style. Initially, I used to declare custom properties for SCG as an ASP.NET Profile object, which offered me two good things for free:
- the intellisense support
- the Profile Object is available on every page, while writing
SCGTemplates
.
I was able to do Profile. (dot) and the VS2005 would create a Profile class on the fly and give intellisense support on the Profile object. And to my knowledge, Code Smith does not have intellisense support on custom properties. I was quite happy with it but when I wanted to write a version of SCG that will support .NET 1.1 as well, I soon realized that the Profile object is not available in the ASP.NET 1.1 framework. I had to change my code a bit and introduced the TheProperties
class to serve the same purpose.
public class TheProperties
{
private string _testProperty;
public string TestProperty
{
get
{
return _testProperty;
}
set
{
_testProperty = value;
}
}
}
The way I used to define custom properties changed a bit also - no more tagging, and now custom properties are defined as properties of the class. By doing this change I could use the code snippets feature from VS 2005. If you have code snippets installed, try typing "prop" and press Tab you will see the property is automatically declared for you. I was happier with this solution, but had to sacrifice one thing: I cannot use the System.Web.UI.Page
and System.Web.UI.UserControl
anymore as I need the TheProperties
in SCGTemplates for intellisense. I had to write ScPageBase
and ScTemplateBase and add TheProperties
as a custom property, so it is carried on the Pages and SCGTemplates
.
public class ScPageBase: System.Web.UI.Page
{
…
private object properties;
public object TheProperties
{
get { return properties; }
set { properties = value; }
}
…
}
public class ScTemplateBase: System.Web.UI
{
…
public ScPageBase ParentPage
{
get
{
if (this.Page is ScPageBase)
return ((ScPageBase)this.Page);
throw new Exception("Parent Page is not ScPageBase");
}
}
...
}
If you have already explored any of the SCGTemplate
s, you might have noticed that it inherits from SCTemplateBase
.
public partial class Templates_DefaultTemplate : ScTemplateBase
{
}
The SCG Framework picks up properties that are defined in this TheProperties
class using reflection and generates a relevant UI for the end user. This cool feature comes out of the box but the SCG Framework does not force you to use these generated UIs for custom properties. You can write your own wizard and collect data for custom properties and pass any custom object to the TheProperties
object of the ScPageBase
. Then, it will be available to all the SCGTemplates with full intellisense support. You should have already noticed that the TheProperies
object of the ScPageBase
class expects a System.Object type and you can assign any valid .NET type.
public class ScPageBase: System.Web.UI.Page
{
…
private object properties;
public object TheProperties
{
get { return properties; }
set { properties = value; }
}
…
}
SCG offers this flexibility to allow you to create your own custom wizard (entirely in your own style and as per your own requirements) for collecting data for custom properties. Also, as you will write ASP.NET pages for your wizard, it is probably one of the easiest to write and extend.
Generate UI for Custom Properties
Here I'll describe how the UI is generated on the fly. The SCG Framework picks up the object passed to the TheProperities
object of the ScPageBase
class and uses reflection to discover its properties. Then it iterates through them and checks if there is any UI element mapped for this .NET Type and generates them on the page.
protected void _LoadUIProperties(object sender, EventArgs e)
{
…
object profile = this.TheProperties;
foreach (PropertyInfo info in profile.GetType().GetProperties())
{
…
if (info.PropertyType.IsPublic)
{
foreach (PropertyTypeAndUIPropertyMap map in
this.UIPropertyMapCollection)
{
if (map.PropertyType == info.PropertyType.ToString())
{
UserControl ctl = _Util.LoadControl(Page,
string.Format("~/PropertyControls/{0}",
map.PropertyUI), info);
ctl.ID = info.Name;
control.Controls.Add(ctl);
break;
}
}
}
}
}
A .NET type and a UIproperty
is mapped in the PropertyAndUIPropertyMaps.xml file which you will find in the root folder of an SCG Project. By opening the file you will see something similar to this:
<?xml version="1.0"?>
<ArrayOfPropertyTypeAndUIPropertyMap xmlns:xsi="http://www.w3.org/
2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<PropertyTypeAndUIPropertyMap>
<PropertyType>System.String</PropertyType>
<PropertyUI>ScStringUIProperty.ascx</PropertyUI>
</PropertyTypeAndUIPropertyMap>
…
</ArrayOfPropertyTypeAndUIPropertyMap>
This file contains an array of PropertyTypeAndUIPropertyMap
which is de-serialized and loaded into UIPropertyMapCollection
.
If you carefully examine any of the PropertyTypeAndUIPropertyMap
nodes you will be able to notice a very simple mapping of a fully qualified name of a .NET Type to an ascx usercontrol e.g. the System.String is mapped to ScStringUIProperty.ascx.
Now you might be asking where the SCG Framework will find the ScStringUIProperty.ascx file. If you open up any of your SmartCodeGenerator Projects you will notice there is a Folder named "PropertyControls". SCG Framework looks for the mapped ascx usercontrols in this folder. In addition, all the ascx controls that are mapped in the above XML file were stored in this folder.
Identify Templates and Output Path
In an Onclick
event of the generate button, the SCG Framework generates text based output from SCGTemplates
, but how does the framework know about which templates to call? To understand this, please open the Default.aspx.cs file and look at the _Default_OnPreGenerator
method. You will see something similar to the following:
void _Default_OnPreGenerate(object sender, EventArgs e)
{
//You can use the handy IOList to Map Input Template and OutputPath
//Add any number of InputTemplateAndOutputPath object to the IOList
//To generate codes in batch mode just iterate through the IOList
this.IOList.Add(new InputTemplateAndOutputPath(
"~/Templates/FirstTemplate.ascx",
@"c:\temp\FirstTemplate.cs"));
this.IOList.Add(new InputTemplateAndOutputPath(
"~/Templates/SecondTemplate.ascx", @"c:\temp\Second.cs"));
this.IOList.Add(new InputTemplateAndOutputPath(
"~/Templates/ThirdTemplate.ascx", @"c:\temp\Third.cs"));
….
}
Notice the framework comes with the InputTemplateAndOutputPath
Class where you can define an input template location and an output path location. In the above code I have simply added a couple of InputTemplateAndOutputPath
objects to the IOList collection.
The ScPageBase
class comes with this IOList collection to facilitate batch mode code generation.
public class ScPageBase: System.eb.UI.Page
{
…
private InputTemplateAndOutputPathCollection ioList = null;
public InputTemplateAndOutputPathCollection IOList
{
get
{
if (ioList == null)
ioList = new InputTemplateAndOutputPathCollection();
return ioList;
}
}
…
}
So, your Templates folder may end up having hundreds of templates but you can run your desired templates from this section. Simply map your desired input and output (using the InputTemplateAndOutputPath
object) and add them to the list object (IOList) like I did above.
At this stage, we have to add objects to the IOList manually by writing code, but a UI / Wizard could be created to map InputTemplate
and OutputPath
. While designing the UI the one thing we have to keep in mind is we have to let the framework know where to read the template from and where to generate output. In future I have plans to write a UI/Wizard to ease up the mapping process.
Generate Output
This is the final step where I generate the output. Open up the default.aspx.cs file. Notice what is done in the following 2 methods.
void _Default_OnGenerate(object sender, EventArgs e)
{
GenerateFiles(IOList, e);
}
private void GenerateFiles(InputTemplateAndOutputPathCollection ioList,
EventArgs e)
{
//This is going to Loop through all the templates of IOList
foreach (InputTemplateAndOutputPath io in ioList)
{
…
_Util.GenerateOutputAsFile(Page, io, e);
//To Get GeneratedText use the following Method
//string generatedText = _Util.GeneratedOutputAsText(Page, io, e);
}
}
Here I iterate through the InputOutputTemplate list (IOList) and generate files by calling _Util.GenerateOutputAsFile
method that comes with the SmartCodeGenerator Framework. I also provided the _Util.GeneratedOutputAsText
method which will return the generated output as string.
Let's now look at the SCG Framework from the pipelines point of view. I will discuss in this section DefaultPage
, SCPageBase
, SCEventArgs
and the SCG Pipelines.
The Default Page
The Default Page has a huge responsibility in the SCG Framework. It coordinates among the responsibilities mentioned above. It acts as the host for the UI and offers a Generate Button to enable text based output. In addition, it reports which files are generated. The Default page inherits from ScPageBase
class and hooks itself in to some of the events in the SCG Framework. Let's look at them in detail.
public partial class _Default : ScPageBase
ScPageBase Events
ScPageBase
Events can be categorized according to their responsibilities as follows:
LoadUIProperty Pipeline:
OnPreLoadUIProperties
: Called beforeUIProperty
is generated.OnLoadUIProperties
: Called duringUIProperty
generation.OnLoadUIPropertiesComplete
: Called afterUIProperty
generation
Generate (Output) Pipeline:
OnPreGenerate
: Called before generating output.OnGenerate
: Called during output generation.OnGenerateComplete
: Called after output generation is complete.OnCleanTheProperties
: A final event to allow cleaning.
Before going deeper in to the discussion, I also want to introduce the ScEventArgs
class.
public class ScEventArgs : EventArgs
{
public Hashtable Item;
public ScEventArgs(Hashtable item)
{
this.Item = item;
}
}
The ScEventArgs
class simply inherits from EventArgs
and has a Hashtable property named Item in it. Now you might be asking why I added a Hashtable object? This will act as a property bag in the pipeline and can be accessed anywhere along the pipeline. If you look at the Page_Load
event of the Default page you will see the following piece of code:
Hashtable dict = new Hashtable();
dict.Add("control", PanelProperties);
ScEventArgs args = new ScEventArgs(dict);
LoadUIProperties_PipeLine(sender, args);
Here I created a Hashtable
object dict
and called the ScPropertyBase.LoadUIProperties_PipeLine
method and passed the PanelProperties
(ASP.NET Panel) in the pipeline as part of the ScEventArgs
.
LoadUIProperties Pipeline
public void LoadUIProperties_PipeLine(object sender, EventArgs e)
{
PreLoadUIProperties (sender, e);
LoadUIProperties (sender, e);
LoadUIPropertiesComplete(sender, e);
}
The LoadUIProperties_Pipeline
calls PreLoadUIProperties
, LoadUIProperties
and LoadUIPropertiesComplete
in sequence. You can use these events and hook your own code and they will be fired. By default, what I do is I hook up some codes to the this.OnLoadUIProperties
event that uses reflection to iterate through the properties of TheProperties
class and load the UI for custom properties. The complete code looks like the following:
protected void Page_Init(object sender, EventArgs e)
{
//Assign TheProperties object
this.TheProperties = new TheProperties();
//Hook UI loading feature for custom properties
this.OnLoadUIProperties += new EventHandler(_LoadUIProperties);
}
protected void Page_Load(object sender, EventArgs e)
{
//Pass panel into pipeline
Hashtable dict = new Hashtable();
dict.Add("control", PanelProperties);
//
ScEventArgs args = new ScEventArgs(dict);
//Execute Pipe_Line
LoadUIProperties_PipeLine(sender, args);
}
protected void _LoadUIProperties(object sender, EventArgs e)
{
…
object profile = this.TheProperties;
foreach (PropertyInfo info in profile.GetType().GetProperties())
{
…
if (info.PropertyType.IsPublic)
{
foreach (PropertyTypeAndUIPropertyMap map in
UIPropertyMapCollection)
{
if (map.PropertyType == info.PropertyType.ToString())
{
UserControl ctl = _Util.LoadControl(Page,
string.Format("~/PropertyControls/{0}",
map.PropertyUI), info);
ctl.ID = info.Name;
control.Controls.Add(ctl);
break;
}
}
}
}
}
The above code is self explanatory.
Generate (Output) Pipeline
If you open up the Default.aspx.cs file you will see the following piece of code:
protected void btnGenerate_Click(object sender, EventArgs e)
{
//Executes the Generate_Pipeline [ this executes OnPreGenerate, OnGenerate,
OnGenerateComplete & OnCleanTheProperties event ]
//Prepare ScEventArgs and pass it to the PipeLine
Hashtable dict = new Hashtable();
ScEventArgs args = new ScEventArgs(dict);
Generate_PipeLine(sender, args);
}
public void Generate_PipeLine(object sender, EventArgs e)
{
PreGenerate(sender, e);
Generate(sender, e);
GenerateComplete(sender, e);
//Clean TheProperties to avoid serialization issue
CleanTheProperties(sender, e);
}
There is another pipeline for generating text based output and this pipeline is executed when the Generate button is clicked. In the OnClick
event of the Generate button I prepare an ScEventArgs
object and pass it to the pipeline. The Generate_Pipeline
calls PreGenerate
, Generate
, GenerateComplete
and CleanTheProperties
in sequence. You will find this pipeline more interesting as all the UIProperties
and SCGTemplates
are hooked in to this pipeline. Open up any UIProperty
in your project you will notice this following pattern, here the code snippet from ScStringUIProperty
:
public ScStringUIProperty(PropertyInfo propertyInfo)
{
ParentPage.OnPreGenerate += new EventHandler(
ScStringUIProperty_OnPreGenerate);
…
}
void ScStringUIProperty_OnPreGenerate(object sender, EventArgs e)
{
string property = tbProperty.Text;
if (propertyInfo.CanWrite)
this.propertyInfo.SetValue(ParentPage.TheProperties, property, null);
}
In the constructor I hook up this UIProperty
to the ParentPage.OnPreGenerate
event handler, and in this case the parent page is the Default.aspx page. This is done as I need to ensure that the text based output is generated with the end user's most recent input. Here I updated the TheProperties
object with the end user's most recent entered data in the textbox.
If you open the Default.aspx.cs page you will also notice that I hooked up a couple other methods to the pipeline as well. Let's explore them.
protected void Page_Load(object sender, EventArgs e)
{
this.OnPreGenerate += new EventHandler(_Default_OnPreGenerate);
this.OnGenerate += new EventHandler(_Default_OnGenerate);
this.OnGenerateComplete += new EventHandler(_Default_OnGenerateComplete);
}
void _Default_OnPreGenerate(object sender, EventArgs e)
{
…
this.IOList.Add(new InputTemplateAndOutputPath(
"~/Templates/Example3Template.ascx",
@"c:\tmp\nainai\{0}TestEntity1.cs"));
//Adding a report item in the args
((ScEventArgs)e).Item.Add("report", string.Empty);
lblReport.Text = string.Empty;
}
void _Default_OnGenerate(object sender, EventArgs e)
{
GenerateFiles(IOList, e);
}
void _Default_OnGenerateComplete(object sender, EventArgs e)
{
lblReport.Text = ((ScEventArgs)e).Item["report"].ToString();
}
The above code is fairly self explanatory. In the OnPreGenerate
event handler I prepare the IOList collection object, add a "report" object to the ScEventArgs
object and pass it in the pipeline. Then in the OnGenerate
event handler I call the GenerateFiles
method (I am coming to this method in a moment) and finally in the OnGenerateComplete
event handler I retrieve the "report" object from the pipeline and display the data in an ASP.NET Label control. As a result you see similar output of the report as below:
OK, let's explore the GenerateFiles
Method in more detail:
private void GenerateFiles(InputTemplateAndOutputPathCollection ioList,
EventArgs e)
{
//This is going to Loop through all the templates of IOList
foreach (InputTemplateAndOutputPath io in ioList)
{
…
_Util.GenerateOutputAsFile(Page, io, e);
//To Get GeneratedText use the following Method
//string generatedText = _Util.GeneratedOutputAsText(Page, io, e);
}
}
Here, I iterate through the IOList collection and can call the _Util.GenerateOutputAsFile
or _Util.GenerateOutputAsString methods. Also, notice the "e" object is passed.
public void GenerateOutputAsFile(Page page, InputTemplateAndOutputPath io,
EventArgs e)
public void GenerateOutputAsFile(Page page, InputTemplateAndOutputPath io,
EventArgs e)
{
string code = string.Empty;
UserControl ctl = page.LoadControl(io.InputPathFilename) as UserControl;
code = GetGeneratedTemplateCode(ctl, e);
//Check Directory and if necessary Create
FileInfo info = new FileInfo(io.OutputPathFilename);
if (!Directory.Exists(info.DirectoryName))
Directory.CreateDirectory(info.DirectoryName);
//Create File
using (StreamWriter sw = File.CreateText(io.OutputPathFilename))
{
sw.Write(code);
}
}
Here, I dynamically load the mapped UserControl
and write the string retrieved from GetGeneratedTemplate
method to file. Notice the "e" object has been passed to the GetGeneratedTemplate
method.
Finally, this is the magical piece of code called GetGeneratedTemplateCode
that enabled me to create SmartCodeGenerator.
private string GetGeneratedTemplateCode(UserControl ctl,
EventArgs e)
{
string code = string.Empty;
if (ctl is ScTemplateBase)
{
((ScTemplateBase)ctl).PreGenerateTemplateCode(this, e);
code = GetGeneratedTemplateCode(((ScTemplateBase)ctl));
//ah feeling light
ctl = null;
}
return code;
}
private string GetGeneratedTemplateCode(ScTemplateBase ctrl)
{
StringBuilder stringBuilder = new StringBuilder();
StringWriter stringWriter = new StringWriter(stringBuilder);
HtmlTextWriter writer = new HtmlTextWriter(stringWriter);
ctrl.RenderControl(writer);
return stringBuilder.ToString();
}
It is not rocket science. ctrl.RenderControl
does the whole job. Here, I also call the PreGenerateTemplateCode
method and pass "e" object. Look carefully at this piece of code:
((ScTemplateBase)ctl).PreGenerateTemplateCode(this, e);
This is why all SCGTemplates
that you write needs to inherit from the ScTemplateBase
class and need to implement the method PreGenerateTemplateCode
. You can also notice that the "e" object is passed to all the SCGTemplates so if you need to use it in any template, you can. This can also act as a propertybag to communicate among the templates. So, the pipeline passes the ScEventArgs
object all the way like this:PreGenerate
=> Generate
=> GenerateComplete
=> CleanTheProperties
.
public partial class Templates_Example2Template : ScTemplateBase
{
public override void PreGenerateTemplateCode( object sender, EventArgs e)
{
//e is accessible here
theclassname = TheProperties.ClassName;
}
}
And finally if you need to do any clean up, you can do this using the OnCleanTheProperties
event.
The DBSchemaProvider
With SmartCodeGenerator you get a Database Schema Discovery API for MS SQL Server, Oracle and the MySQL database engines. I have used Microsoft® Provider Design Pattern to write the Schema Discovery API. For a refresher on the Provider Pattern, have a look at my previous article "Flexible and Plug-in-based .NET Applications Using the Provider Pattern". To allow you to discover the database schema details, the providers come with the following signature.
public abstract class DBSchemaProvider : ProviderBase
{
// Methods
protected DBSchemaProvider();
public abstract ParameterSchemaCollection
GetCommandParameters(CommandSchema command);
public abstract CommandResultSchemaCollection
GetCommandResultSchemas(CommandSchema command);
public abstract CommandSchemaCollection GetCommands(DatabaseSchema
database);
public abstract string GetCommandText(CommandSchema command);
public abstract string GetDatabaseName(DatabaseSchema database);
public abstract string GetDescription();
public abstract ExtendedPropertyCollection
GetExtendedProperties(SchemaBase schemaObject);
public abstract string GetName();
public abstract ColumnSchemaCollection GetTableColumns(TableSchema table);
public abstract DataTable GetTableData(TableSchema table);
public abstract IndexSchemaCollection GetTableIndexes(TableSchema table);
public abstract TableKeySchemaCollection GetTableKeys(TableSchema table);
public abstract PrimaryKeySchema GetTablePrimaryKey(TableSchema table);
public abstract TableSchemaCollection GetTables(DatabaseSchema database);
public abstract ViewColumnSchemaCollection GetViewColumns(ViewSchema view);
public abstract DataTable GetViewData(ViewSchema view);
public abstract ViewSchemaCollection GetViews(DatabaseSchema database);
public abstract string GetViewText(ViewSchema view);
public static DBSchemaProvider Instance();
public static DBSchemaProvider Instance(string providerName);
}
To write a new provider for a different database all you have to do is implement these methods. All the source code of how I implement providers for MS SQL Server, Oracle and MySQL is available for download from CodePlex.
Writing SCG Templates and Using SmartCodeGenerator
There is nothing new to learn here if you already know how to write an ascx UserControl. All you have to do is write an ascx UserControl, but remember to inherit the UserControl from ScTemplateBase
class and make sure you implement the PreGenenerateTemplateCode
method. Here is an example of the codebehind:
public partial class Templates_Example2Template : ScTemplateBase
{
public override void PreGenerateTemplateCode( object sender, EventArgs e)
{
//e is accessible here
theclassname = TheProperties.ClassName;
}
}
And here is a simple example of a SCGTemplate
<%@ Control Language="C#" AutoEventWireup="true"
CodeFile="Example2Template.ascx.cs"
Inherits="Templates_Example2Template" %>
public class
<%=TheProperties.ClassName%>
{
public <%=TheProperties.ClassName%>()
{
//Add constructor here
<%for (int i = 0; i < 3; i++)
{
%>
//Hey this is Cool
<%} %>
}
}
For more details on how to write templates and how to use SmartCodeGenerator please refer to the tutorials at http://www.smartcodegenerator.com.
How to write your own UIProperty
You can introduce UIProperties
for any .NET Type that you wish to use. At this stage, you get UIProperties for string, int, boolean, enum, StringCollection, MandatoryString and ScTableSchema etc. provided for you. However, UIProperties
are also ascx controls and are very easy to write. For a complete tutorial on how to write UIProperties
please refer to this post at Team Blog (Introducing New UIProperty in SmartCodeGenerator). If you happen to write any new UIProperty
or SCGTemplate
, I would request you to share them with the community and upload them to the forum site of SmartCodeGenerator: SmartCodeGenerator Community Site. You can also download SCGTemplates
and UIProperties
shared by the community from this site.
Conclusion
SmartCodeGenerator is a very powerful code generation framework. Here it couples Visual Studio and ASP.NET. However, this framework can be used with any ASP.NET IDE that exists in the world and code can be generated. You simply need to create an ASP.NET project, add a reference to the DLLs supplied with SCG. SCG also ships with Database Schema Discovery API's for MS SQL Server, Oracle and MySQL, and implementing new providers for different databases is very easy. An SCG Project is simply a ASP.NET project and not dependent on any third party tools, and SCGTemplates and UIProperties are ascx UserControls. For a ASP.NET developer there is nothing new to learn to start using SmartCodeGenerator. I strongly believe that you will agree with me in saying: "Code Generation has never been this easy".
Thank you for being with me so far and please join the community and share your SCGTemplates and UIProperties.
Proof reading done by: Christopher Heale
Resources and Links related to SmartCodeGenerator
- Download source code and releases at Codeplex.
- Community: SmartCodeGenerator Community Site.
- Community Forums: Discussions Page
- Tutorials: SmartCodeGenerator Quick start v2.0.
- Team Blog: Team Blog
- And My Blog: Shahed Khan (MVP).