Click here to Skip to main content
15,867,568 members
Articles / Web Development / ASP.NET
Article

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

Rate me:
Please Sign up or sign in to vote.
4.30/5 (16 votes)
23 Mar 200716 min read 101.9K   1.5K   114   15
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.

Sample Image - smartcodegenerator.gif

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.

    Image 2

    C#
    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.

    Image 3
    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.

    Image 4

    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:
    Image 5

    • OnPreLoadUIProperties: Called before UIProperty is generated.
    • OnLoadUIProperties: Called during UIProperty generation.
    • OnLoadUIPropertiesComplete: Called after UIProperty generation

    Generate (Output) Pipeline:
    Image 6

    • 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.

    Image 7

    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.

    Image 8


    C#
    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.

    Image 9

    C#
    public class ScPageBase: System.Web.UI.Page
    {
      …
      private object properties;
      public object TheProperties
      {
        get { return properties; }
        set { properties = value; }
      }
      …
    }

    Image 10

    C#
    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 SCGTemplates, you might have noticed that it inherits from SCTemplateBase.

    C#
    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.

    Image 11

    C#
    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.

    C#
    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
    <?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.

    Image 12

    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:

    C#
    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.

    Image 13

    C#
    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.

    C#
    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

    Image 14

    ScPageBase Events

    ScPageBase Events can be categorized according to their responsibilities as follows:

    LoadUIProperty Pipeline:

    • OnPreLoadUIProperties: Called before UIProperty is generated.
    • OnLoadUIProperties: Called during UIProperty generation.
    • OnLoadUIPropertiesComplete: Called after UIProperty 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.

    Image 15

    C#
    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:

    C#
    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

    Image 16

    C#
    public void LoadUIProperties_PipeLine(object sender, EventArgs e)
    {
        PreLoadUIProperties (sender, e);
        LoadUIProperties (sender, e);
        LoadUIPropertiesComplete(sender, e);
    }

    Image 17

    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:

    C#
    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:

    C#
    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);       
    }

    Image 18

    C#
    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);
    }

    Image 19

    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:

    C#
    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.

    C#
    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:

    Image 20

    OK, let's explore the GenerateFiles Method in more detail:

    C#
    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.

    C#
    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.

    C#
    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:

    C#
    ((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.

    C#
    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.

    Image 21

    C#
    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:

    C#
    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

    C#
    <%@ 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

  • License

    This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

    A list of licenses authors might use can be found here


    Written By
    Web Developer
    Australia Australia
    I have been awarded MVP (Visual C#) for year 2007, 2008, 2009. I am a Microsoft Certified Application Developer (C# .Net). I currently live in Melbourne, Australia. I am a co-founder and core developer of Pageflakes www.pageflakes.com and Founder of Simplexhub, a highly experienced software development company based in Melbourne Australia and Dhaka, Bangladesh. Simplexhub.
    My BLOG http://www.geekswithblogs.net/shahed
    http://msmvps.com/blogs/shahed/Default.aspx.

    Comments and Discussions

     
    QuestionHow to Add additional custom code in aspx code behind Pin
    Vikas Parikh12-Feb-08 21:39
    Vikas Parikh12-Feb-08 21:39 
    GeneralError when trying with Oracle [modified] Pin
    Martin Aathanya6-Aug-07 1:44
    Martin Aathanya6-Aug-07 1:44 
    GeneralRe: Error when trying with Oracle Pin
    Shahed.Khan7-Aug-07 15:00
    Shahed.Khan7-Aug-07 15:00 
    GeneralDiagrams Pin
    Bill Seddon27-Mar-07 12:04
    Bill Seddon27-Mar-07 12:04 
    GeneralVery nice Pin
    astodola27-Mar-07 3:22
    astodola27-Mar-07 3:22 
    QuestionCan it be used with Enterprise library? Pin
    devnet24713-Feb-07 22:00
    devnet24713-Feb-07 22:00 
    Hi,Not much time to look at it.But can your generator work with EnterpriseLibrary 2.0?
    Do you also have an example project that has been generated by your tool?
    Thanks




    thanks a lot

    AnswerRe: Can it be used with Enterprise library? Pin
    Shahed.Khan14-Feb-07 12:08
    Shahed.Khan14-Feb-07 12:08 
    GeneralGenius Pin
    Justin Keyes9-Feb-07 13:17
    Justin Keyes9-Feb-07 13:17 
    GeneralRe: Genius Pin
    Shahed.Khan9-Feb-07 14:19
    Shahed.Khan9-Feb-07 14:19 
    GeneralDLL Pin
    Nagarajanp24-Jan-07 21:57
    Nagarajanp24-Jan-07 21:57 
    GeneralRe: DLL Pin
    Shahed.Khan27-Jan-07 15:52
    Shahed.Khan27-Jan-07 15:52 
    GeneralProfile Object Version Pin
    Nagarajanp22-Jan-07 23:52
    Nagarajanp22-Jan-07 23:52 
    GeneralRe: Profile Object Version Pin
    Shahed.Khan23-Jan-07 13:45
    Shahed.Khan23-Jan-07 13:45 
    GeneralGood work + Questions. Pin
    ggeurts8-Jan-07 12:52
    ggeurts8-Jan-07 12:52 
    GeneralRe: Good work + Questions. Pin
    Shahed.Khan8-Jan-07 15:51
    Shahed.Khan8-Jan-07 15:51 

    General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

    Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.