Angel \”Java\” Lopez on Blog

July 14, 2009

ASP.NET example using Mere Mortals Framework

Filed under: .NET, ASP.NET, Mere Mortals Framework, Visual Basic .NET — ajlopez @ 8:31 am

I was working reproducing the ASP.NET example described in Mere Mortals Framework Developer’s Guide, using Northwind MS SQL database, using VB.NET as implementation language (the guide explains the steps to create this app using VB.NET or C#).

You can download the result from my Skydrive:

MMNorthwind.zip

Load the solution in VS 2008 (you must have Mere Mortals Fwk DLLs in your machine).

This is the CustomerOrders.aspx page:

The first column is a link, that points to OrderEdit.aspx, where you can edit

You can change the connection string at web.config:

In my current project, the team is working improving the validation process, specially in grid fields. I hope I will rewrite this example as templates and tasks using AjGenesis. Keep tuned!

Angel “Java” Lopez
http://www.ajlopez.com/
http://twitter.com/ajlopez

June 21, 2009

Code Generation for Mere Mortals Framework

In the current project, my agile team is developing a full health application (Medusa Project), using Mere Mortals Framework as a base to business objects, persistence and WinForm/ASP.NET presentation. You can download a trial version of this framework:

http://www.oakleafsd.com/

There is a feature list at

http://www.oakleafsd.com/MMNetFeatures/pgMMNetFeatures.htm

You can download the developer Guide from

MM .NET Developer’s Guide

The framework were developed by Kevin McNeish, Microsoft MVP, president and Chief Architect of Oak Leaf Enterprise. The framework supports typed entities, but in the background, it’s based on datasets. You can generate a business objects project from templates, and with a code generator provided by the product, you can populate that library with classes, derived from a database.

In my team, we are feeding metadata reading database information, and then, we are generating a full ASP.NET Web Application, a business object libraries, stored procedures, and DDLs for database regeneration. All using AjGenesis, my open source code generation utility. I should post about the experience. The seed task and templates, were derived from the example:

AjGenesis- Generating the model from the database

In this post, I describe another approach: starting from an abstract model, I’m generating:

– Scripts for creating the database
– Business Objects a la Mere Mortals class library
– WinForm project with maintenance forms

I posted about generating applications from an abstract model at:

Application Generation using AjGenesis

but caveat: AjGenesis is based in a free model. You can model what you want. The trivial example:

Code Generation with AjGenesis- A Hello World application

The model

You can download the example from the Codeplex project site example page:

MereMortalsExamples200906.zip

It contains:

The model resides in Projects/AjFirstExample/Project.xml

<Project>

    <Name>AjFirstExample</Name>

    <Description>First Example using AjGenesis</Description>

    <Prefix>AjFE</Prefix>

    <Domain>com.ajlopez</Domain>

    <CompanyName>ajlopez</CompanyName>

    <Model>

        <Entities>

            <Entity Source="Entities/Customer.xml"/>

            <Entity Source="Entities/Supplier.xml"/>

        </Entities>

        <Lists>

            <List Entity="Customer"/>

            <List Entity="Supplier"/>

        </Lists>

        <Forms>

            <Form Entity="Customer"/>

            <Form Entity="Supplier"/>

        </Forms>

        <Views>

            <View Entity="Customer"/>

            <View Entity="Supplier"/>

        </Views>

    </Model>

</Project>

There are two entities, Customer and Supplier. The Customer entity:

<Entity>

    <Name>Customer</Name>

    <Description>Customer Entity</Description>

    <SetName>Customers</SetName>

    <Descriptor>Customer</Descriptor>

    <SetDescriptor>Customers</SetDescriptor>

    <SqlTable>Customers</SqlTable>


    <Properties>

 

        <Property>

            <Name>Id</Name>

            <Type>Id</Type>

        </Property>

 

        <Property>

            <Name>Name</Name>

            <Type>Text</Type>

            <SqlType>varchar(200)</SqlType>

        </Property>

 

        <Property>

            <Name>Address</Name>

            <Type>Text</Type>

            <SqlType>text</SqlType>

        </Property>

 

        <Property>

            <Name>Notes</Name>

            <Type>Text</Type>

            <SqlType>text</SqlType>

        </Property>

 

    </Properties>

</Entity>

 

There is a technology dependent model at Projects/AjFirstExample/Technologies/VbNet3.xml:

<Technology>

    <Programming>

        <Dialect>VbNet3</Dialect>

    </Programming>

    <Database>

        <Dialect>MsSql</Dialect>

        <Name>AjFirstExampleMM</Name>

        <Host>(local)</Host>

    </Database>

</Technology>

You can change the host to .\SQLEXPRESS if you don’t have a running MS SQL Server. You can add <Username> and <Password> if you are using SQL security. If there are not present, the code uses integrated security.

Generating the application

You must download AjGenesis current release 0.5 from http://ajlgenesis.codeplex.com. Add the bin directory to your path. Then, run from the example directory:

GenerateProject.cmd AjFirstExample VbNet3

The first parameter is the project name, and the second is the technology to use. The command invokes

AjGenesis.Console Projects\%Project%\Project.xml tasks\BuildProject.ajg  Projects\%Project%\Technologies\%Technology%.xml tasks\BuildTechnology.ajg tasks\BuildProg.ajg tasks\BuildSql.ajg

It loads the project model, execute the BuildProject task, then loads the technology model, executes the BuildTechnology tasks. The task BuildProg generates the code, and BuildSql generates the DDL to create the database.

It creates a new folder, Build, containing

In Sql folder, you find the ExecuteAll.cmd to create the database

You can run it with a parameter, specifiying your server:

ExecuteAll.cmd Bombadil

If you run this command without a parameter, it uses the host specified in the technology model. There is a VS 2008 solution with two projects, in Src folder:

You can load and compile in Visual Studio (you must have Mere Mortals Fwk installed).

The class library project contains Mere Mortal business objects definition (using partial classes, data access calling stored procedures, rules)

The Win form project has two maintenance forms, for Customers and Suppliers:

Well, it’s not the “killer application” but it’s running:

You can download the generated solution, from my Skydrive

AjFirstExampleMereMortals.zip

Conclusions

Using an abstract model, we can generate the usual text artifacts required by Mere Mortals fwk (or any other framework, technology). With partial classes and separated files, we can regenerate the code from the model, without losing our manual code. We can augment the generated code with automatic validation, rules, and any coding standard we were using.

But the main point, for me, it’s that using an abstract model, we are separating the important core from the technicalities. I could regenerate the application with other base framework, other languages, but our model could be the same. The model describes what we want. Tasks and templates compose an expert system, that knows HOW to get what we want as application.

Angel “Java” Lopez

http://www.ajlopez.com/en

http://twitter.com/ajlopez

April 19, 2008

Code Generation as a Service with AjGenesis

I’m back! I want to write in this post about the new features I’ve added to my code generation project AjGenesis. The main points are:

– A new interactive way to use it, a web based application

– Examples with that new interface, to generate C#, VB.Net, Java and PHP applications, all from the same abstract model

These features were published last January at release 0.5 in CodePlex

Using AjGenesis

Years ago, I began to work in this project. Those days, the only way to execute and use it were the console, with commands. Later, I adopted NAnt, and NAntGui, as interfaces to launch the system and execute tasks and transformations. The project can be used as a set of .DLLs, referenced from custom application. Carlos Marcelo Santos has published posts (in Spanish) about how to use AjGenesis from NAnt

Cómo generar código con AjGenesis sirviéndonos de NAnt
Cómo generar código con AjGenesis sirviéndonos de NAnt – Parte II

Last year, 2007, Jonathan Cisneros wrote a great Windows interface, named AjGenesis Studio:

AjGenesis Studio: una IDE para AjGenesis
AjGenesis Studio at CodePlex

As an exercise at the end of year 2007, I wrote a new project in the original solution, and I published last January inside the last release 0.5 at CodePlex.

It’s a new web project, that I called, inspired by the work of Jonathan, AjGenesis Web Studio

The main point is, with this project, to show that the functionality from the AjGenesis core can be used and exposed in our applications, this time from a web interface, using ASP.NET. With this approach, we can put a server in our internal network or at Internet, and create, edit, upload and download user defined models, generate source code, and download the results. We could call this, Code Generation as a Service.

Let’s look the project, its functions and some inners.

The project

It’s a web project, named AjGenesis.WebStudio.

To launch it, load the AjGenesis.sln solution (located at src directory inside the version 0.5 from CodePlex) with Visual Studio 2005, and build the complete solution.

(If you have errors in the AjGenesis.WebStudio project, probably you must add a reference to a .DLL that manages the file compressions. Add as reference to the project the file src\Libraries\Ionic.Utils.Zip.dll. This library generates .zip files, and expand them).

In the web solution, I used Master Pages, and a default Theme. It doesn’t manage a database, only files and directories. We’ll see below that the project has a mini wiki, to write help pages that can be defined by the user.

The look and feel is simple, but you can change the theme and master page to obtain a better result.

The system can generate code in the fly, and download it as a .zip file. You can use the classic AjGenesis system, as I explained in past post, but now, we can use it from any browser. You don’t need .NET in your client machine, and you can work from other operating systems.

After the build of the solution, click right mouse button on the file \Default.aspx in project AjGenesis.WebStudio, and choose View in browser…:

This is preferred to launch the project in debug mode: if you debug the project, it will execute the code generation task in very slow way.

Working Directory

The system uses a working directory, with a structure that resembles the examples at AjGenesisExamples3.zip (to download from examples at CodePlex). The default working directory is AjGenesis.WebStudioWorkingDirectory:

Some directories:

Projects: There is a directory here for each project model.
Templates: Containing the template files to process during the code generation phase
Build: The code generated code resides in this directory.

The working directory can be changed using the left menu option Working Directory and then, choosing the option Change Working Directory:

Generating Hello World

As I used to comment in my speeches, the acid test of all code generation system is to help us to model and produce the most simple and universal software system, the reknowed Hello World example. There is an explanation on how to do this with classic AjGenesis in my post

Code Generation with AjGenesis- A Hello World application

In AjGenesis Web Studio, select the left menu option Generate. This is the result page

There are two dropdown list. We’ll see how they are filled. At the first list, there are the defined projects:

Choose HelloWorld. Then, go to technology list, showing:

In this project, only Java and Net20 are the defined technologies. Other projects have more technologies. Choose Java and the press the Generate button. After a while, the page shows a result.

How this works?

First point, the system manage a working directory, the default is AjGenesis.WebStudioWorkDirectory, a syster directory of the web project. There is a Projects project, cointaining more directory, each one is a project for the system.

The directory AjGenesis.WebStudioWorkDirectory\Projects\HelloWorld has a Project.xml file that describes the free model we use in this case:

<Project> <Name>HelloWorld</Name> <Description>HelloWorld Example</Description> <GenerateTask>GenerateHelloWorld</GenerateTask> <Message>Hello World</Message> </Project>

Inside the directory project, there is a Technologies directory. Each XML file that is found there it’s managed as a technology model in the system. Again, as I explained in my posts on AjGenesis , this file has a free model, you can put here anything to process from code generation process. The concepts of project and technology is not mandatory, but AjGenesis Web Studio takes them as special directories, and read them to obtain the list of project and associated technologies.

The technology Java.xml file contains:

<Technology> <Name>Java</Name> </Technology>

and Net20.xml contains:

<Technology> <Name>Net20</Name> </Technology>

Nothing special. The value Name inside Technology drives what steps to execute during code generation phase.

After press the generate button, the system loads the project and technology model in memory. Then, it executes the file GenerateCode.ajg located in directory Tasks. But if the project file contains a  GenerateTask tag, as in this project, that file is executed instead the default one. This is the content of Tasks\GenerateHelloWorld.ajg:

 

PrintLine "Generating HelloWorld..." if not Project.BuildDir then Project.BuildDir = "${WorkingDir}Build/${Project.Name}" end if if not Project.Title then Project.Title = Project.Name end if if not Project.Version then Project.Version = "1.0.*" end if if not Project.Language then Project.Language = "en" end if if not Project.SystemName then Project.SystemName = Project.Name end if PrintLine "Creating Directory ${Project.BuildDir}" FileManager.CreateDirectory("${Project.BuildDir}") Include "Tasks\BuildHelloWorld${Technology.Name}.ajg"

This file is written in an scripting language, a pillar of AjGenesis, affectously named AjBasic. The Project variable is the representation in memory of the tag <Project> loaded from the Project.xml file, described above. In memory, it is as an object, with properties. It’s not an static object: you can add properties in runtime, as Project.Version in the above text. If in an if sentence we asks the value of  Project.Version and this doesn’t exist, it’s not an error, the result is simply Nothing and that value is treated as false for boolean evaluations (like in other languages, notably PHP).

Finally, the last line includes an additional file to process dinamically. The string contants in AjBasic have expression expansion: all between ${ and } is evaluated. Using the value of Technology.Name (obtained from loading in memory the XML technology file), it executes BuildHelloWorldJava.ajg or BuildHelloWorldNet20.ajg. The first one contains the steps to generate a .java file:

<# PrintLine "Generating Solution ${Project.Name}" if not Project.Title then Project.Title = Project.Name end if if not Project.Version then Project.Version = "1.0.*" end if PrintLine "Creating Directories" FileManager.CreateDirectory("${Project.BuildDir}") FileManager.CreateDirectory("${Project.BuildDir}\${Technology.Name}") TransformerManager.Transform("Templates\HelloWorld\ClassJava.tpl", "${Project.BuildDir}\${Technology.Name}\HelloWorld.java", Environment) #>

This code uses inner AjGenesis utilities that create directories and expand a template file. ClassJava.tpl contains:

// // Automatically generated by AjGenesis // http://www.ajlopez.com/ajgenesis // public class HelloWorld { public static void main(String[] args) { System.out.println("${Project.Message}"); } }

All this produces the directory Build\HelloWorld\Java:

If we choose the Net20 technology, more files would be generated:

This is a more complete result. It has a VS 2005 solution file, two project directories, one in VB.NET and the other in C#, with source code and project files:

To see the generated code, its files and directories, go to left menu option Builds:

There is a directory for each project. You can download a complete directory, as a .zip file. We can create a file, download a directory, upload and expand a .zip file, and consult a help page. We can read, edit, and delete each file, in this case readme.txt.

Go to the View at HelloWorld directory:

You can browse directories, upload and download files. You can move a directory, or make a copy, to experiment without loosing the original content.

Generating C# and VB.NET solutions

After this simple example, let’s go for more. For more information about the next examples and their models, read:

Application Generation using AjGenesis

Go again to left menu Generate option. Now, we choose a project, AjSecondExample. Its technology list is more complete:

Choose CSharp2 and generate. This process creates a complete solution inside Builds\AjSecondExample\CSharp2. There is an Sql directory with DDL script to create a MS SQL Server database. Inside the Src directory, you’ll find the solution, composed of a set of projects:

This projects follows a layered archictecture, that you can modify from the templates. They use a data access layer, based on my AjFramework project, but you can change to access Enterprise Library or your own data services.

You must create the database using the generated scripts, and modify the connection string in the web.config to match your environment. The application can be compiled and executed:

The administration page shows:

Back to generate page, execute the VbNet2 technology, obtaining a directory with the same structure, now with Visual Basic.NET code:

All these depend of the specified technology inside the files at Projects\AjSecondExample\Technologies. The content of VbNet2.xml is:

<Technology> <Programming> <Dialect>VbNet2</Dialect> </Programming> <Database> <Dialect>MsSql</Dialect> <Name>AjSecondExample</Name> <Username>sa</Username> <Prefix>ajse_</Prefix> <Host>(local)</Host> </Database> </Technology>

and CSharp2.xml:

<Technology> <Programming> <Dialect>CSharp2</Dialect> </Programming> <Database> <Dialect>MsSql</Dialect> <Name>AjSecondExample</Name> <Username>sa</Username> <Prefix>ajse_</Prefix> <Host>(local)</Host> </Database> </Technology>

These data are used during the code generation process.

Note: inside Tasks\BuildTechnology.ajg file, you’ll find a new variable, injected from the web project:

if not Project.BuildDir then Project.BuildDir = "${WorkingDir}Build/${Project.Name}/${Technology.Programming.Dialect}" end if

This is the WorkingDir variable that points to the working directory we selected in AjGenesis Web Studio.

Genarating Java and JSP applications

Many projects (AjFirstExample, AjSecondExample, AjTest….) can be generated in Java with JavaServer Pages. A build.xml file is generated to be modified and used to compile the generated code using the ant utility (you can use this file from an IDE, like Eclipse or NetBeans).

The target build  makes a .war deploy file. You can browse and modify the build.xml file to install the .war in a Tomcat web container.

The generated code is composed of .jsp files (web pages in Java) and Java code to compile that implements a service layer and a data access layer, exchanging simple JavaBeans between layers. The DDL script, in these examples, is a MySql one.

If you build and deploy the application, and install the database in a MySql server, you can see it working fromn a Tomcat server:

Generating application using Domain-Driven Design ideas and Hibernate, NHibernate

Many example projects (AjFirstExample, AjSecondExample, AjTest…) have defined technologies CSharp2DDDNh, JavaDDDHb, VbNet2DDDNh, and even VbNet2Nh. The DDD ones implement some concepts from Domain-Driven Desigg, as Application, Domain and Infrastructure layer, but the templates could be improved. The *Nh projects generate code for entities using NHibernate mapping. The *Hb projects use Hibernate.

An example of NHibernate generated mapping:

 

<?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.0"> <class name="AjFirstExample.Domain.Customer, AjFirstExample.Domain" table="ajfe_customers"> <id name="Id" column="Id" type="Int32" unsaved-value="0"> <generator class="native"/> </id> <property column="Name" type="String" name="Name" length="255"/> <property column="Address" type="String" name="Address" length="255"/> <property column="Notes" type="String" name="Notes" length="255"/> </class> </hibernate-mapping>

These solution can be built as the previous examples. You’ll see better generator templates for NHibernate in the AjOmar example at CodePlex. Post (in Spanish) explaining the process at

Generando código para NHibernate (Parte 1)
Generando código para NHibernate (Parte 2)
Generando código para NHibernate (Parte 3)

Generating PHP applications

If you choose PHP technology, web page with PHP code are generated, using MySql as database. The generated code can be copied to a directory in a web site that supports PHP, Apache, or IIS. AjTest example running in a IIS with PHP4:

Other directories

In the working directory, there are other directories:

SourceCode: Containing some source code that is copied into the solution during code generation.

Libraries: Additional .dlls, to copy and use in the generated applications.

The larger subdirectory  is Templates:

In previous posts I described in detail the creation and use of a template file. This is the content of a template that generate a C# entity:

<# rem Entity Generator rem for C Sharp include "Templates/CSharp2/CSharpFunctions.tpl" message "Processing Entity ${Entity.Name}" include "Templates/CSharp2/Prologue.tpl" #> /* * Project ${Project.Name} * ${Project.Description} * Entity ${Entity.Name} * ${Entity.Description} * */ using System; namespace ${Project.SystemName}.Entities { public class ${Entity.Name} { // Private Fields <# for each Property in Entity.Properties message "Processing Field ${Property.Name}" #> private ${CSharpType(Property)} ${CSharpFieldName(Property)}; <# end for #> // Default Constructor public ${Entity.Name}() { } // Public Properties <# for each Property in Entity.Properties message "Processing Property ${Property.Name}" #> public ${CSharpType(Property)} ${Property.Name} { get { return ${CSharpFieldName(Property)}; } set { ${CSharpFieldName(Property)} = value; } } <# end for #> } }

Help pages

I’m testing some ideas in this web project. There are code to create “wiki” pages, that can be used as help pages in the system.

You can edit this kind of pages:

There is a way to insert links to other wiki pages and to external ones. The page data is represented as a .NET object in memory, and that object is serialized in an XML file in Pages application directory. There is no database to store page: each one is an object, serialized in a .xml file.

Conclusions

I hope this system helps to a better understanding of AjGenesis project features and potential. With a more user friendly interface, the project can be used by more people. We can generate code from command line, or using NAnt utility, or AjGenesis Studio.

I ever remark a point: all these are examples, AjGenesis is not limited to generate only this kind application. You are in charge: you can define the model that matches your project requirements, using any technology you choose. You can codify DDD ideas in a different and better way. You can generate Hibernate/NHibernate mappins using other patterns and mapping idioms. You can use other ORM utilities, and generate code for them. You can generate PHP5 pages that use Prado, instead of plain PHP4. You can generate stored procedures for Oracle, instead of my examples that use MS SQL Server. Or write better ones. You can generate WinForms code, instead of ASP.NET page. You can generate JavaServer Faces pages, views, beans, and abandon JavaServer Pages. You can generate the code or text you want: e.g., unit tests, or documentation pages. I recommend that the generated code resembles the code you could generate manually.

I invite anyone that uses this system, to post his/her work, or leave comments here. You can participate in the Spanish list:

http://groups.google.com/group/codegeneration?hl=es

Next steps

Back to develop, I have some ideas:

– Improve the templates to generate more technologies, as VS 2008 projects, solutions, templates for Struts 1/2, Spring, better mapping for Hibernate, NHibernate, and code generation for the new ASP.NET MVC.

– Write posts about these templates

– Publish the new examples

– Write down a useful documentation (now, it’s minimal: you can found more details in this posts)

Enjoy the project!

Angel “Java” Lopez
http://www.ajlopez.com/en

November 12, 2007

Application Generation using AjGenesis

These days, I wrote new examples for my open source project AjGenesis

http://www.ajlopez.com/ajgenesis
http://www.codeplex.com/ajgenesis

Using AjGenesis, we can produce, starting from our own model, applications for ASP.NET 1.x/2.x, JSP, using SQL Server in .NET, with ADO.NET or NHibernate, or MySql with Java and Hibernate. The sample generated applications use a layered architecture (but remember: these are sample applications, you can write and use your own models, tasks, and templates). Other option: it can generate layers following ideas from Eric Evans’ Domain-Driven Design.

I’m still writing those examples, but now, you can download the current version from

AjGenesisExamples3New.zip

The examples require the use of AjGenesis last release:

AjGenesis Version 0.4.3

but you can try the current version under development:

AjGenesis Version 0.5

In this post, I want to comment how AjGenesis works and some of its inner structure, using one of those examples. Although I will concentrate in producing VB.NET code, you’ll find that the example is able to produce C Sharp and Java/JSP solutions, as well.

First, let’s review first some points about the project. The big picture:

AjGenesis Version 0.4.3 is written using VB.NET V1.x, but version 0.5 is the current version under development, and it was rebuilt using .NET 2.0. The project is open source, and has a BSD-like license, that allows to use it in any project what you want: you only need to comply with the license (in short, put some reference to the original project). It is possible to be used like a library, invoked from your own project, or it is possible to be invoked from command line, or even it can be used from using NAnt (this tool gives you a better organization of the code generation tasks).

There are several samples in the page of the project (inside the project zip source file and in additional files). They generate code from a model, invoking tasks and processing templates. The samples generate code PHP, Java, JSP, VB.NET, C#, ASP.NET, and even scripts of procedure and data base stored. I want to emphasize two points:

The model to use is totally definible by you. It’s a free model, it’s not a fixed one. You can model what you want to model.

– The tasks and templates to apply are totally programmable and controlable. You are in charge. 

That’s make a difference from other generators. We can create our own model, and its own templates and tasks, to generate any text artifacts. Other systems start from the data base, and they only generate a group of predefined text files (as POJOs, plain old java objects, or DAOs, Data Objects Access). But with AjGenesis you can generate any text file you need.

In order to better understandind the free model concept, read a previous post:

Generating Code Hello World with AjGenesis

In that post, the initial steps are described, using a free model, totally oriented to the domain to represent: a typical Hello World application, implemented in different technologies.

Creating an application

Let’s do something more complete in this post. Suppose we need to create a simple solution simple, with two tables, in a MS SQL Server databse, source code in VB.NET 2,0, web interface, layer of services, layer of data, business components and business entities a la Microsoft. We want to generate the solution, the projects, scripts for database creation, and stored procedures. This example is included in the examples AjGenesisExamples3New.zip. First step: to write the model.

The project

In a directory of projects of the examples that accompany this article, there is a Projects/AjFirstExample directory.

In that directory it is the Project.xml file that contains the model.

<Project>
    <Name>AjFirstExample</Name>
    <Description>First Example
    using AjGenesis</Description>
    <Prefix>AjFE</Prefix>
    <Domain>com.ajlopez</Domain>
    <CompanyName>ajlopez</CompanyName>
    <Model>
        <Entities>
            <Entity
            Source="Entities/Customer.xml"/>
            <Entity
            Source="Entities/Supplier.xml"/>
        </Entities>
    </Model>
</Project>

Remember: the model is free. Here we define the templates that we are going to use. The model contains two simple entities: customers and suppliers.

The entities

The XML file is not terribly long: AjGenesis allows that any node of the model is specified apart in a file. This is a criterion that I have used to define how the model is written: the resulting XML does not have to hurt at sight, must be understandable and abarcable in a reading.

In the Project.xml, that feature is used in the case of the entities, with the Source attribute. Let us examine an entity, written in Entities/Customer.xml:

<Entity>
    <Name>Customer</Name>
    <Description>Customer Entity</Description>
    <SetName>Customers</SetName>
    <Descriptor>Customer</Descriptor>
    <SetDescriptor>Customers</SetDescriptor>
    <SqlTable>customers</SqlTable> 

    <Properties> 

        <Property>
            <Name>Id</Name>
            <Type>Id</Type>
        </Property> 

        <Property>
            <Name>Name</Name>
            <Type>Text</Type>
            <SqlType>varchar(200)</SqlType>
        </Property> 

        <Property>
            <Name>Address</Name>
            <Type>Text</Type>
            <SqlType>text</SqlType>
        </Property> 

        <Property>
            <Name>Notes</Name>
            <Type>Text</Type>
            <SqlType>text</SqlType>
        </Property> 

    </Properties>
</Entity> 

There are attributes of the entities, like its name and description, in plural and singular. This data serve to name them in the resulting pages, or within the code. The properties are the fields to maintain in each entity..

Aside from the entities, in another directory, Technologies, specifies the dependent model of the technology, like VbNet2:

The templates

The templates to use are at the Templates/VbNet2 directory:

They are the templates for generation of code VB.Net 2.0. Also we will find groups for C# 1/2, Vb.NET 1,2, Java (although I’m thinking to drop templates for .NET 1.x: I don’t see any reason to maintain these). There are templates to use Nhibernate, Hibernate, JSP, MySql, and concepts of Domain-Driven Design, too. Let’s review a template as an example, the one that generates the organization in Visual BASIC, EntityVb.tpl:

<# 

message "Generating Entity ${Entity.Name}" 

include    "Templates/VbNet2/VbFunctions.tpl" 

include    "Templates/VbNet2/Prologue.tpl"
#> 

'
'    Project ${Project.Name}
'        ${Project.Description}
'    Entity    ${Entity.Name}
'        ${Entity.Description}
'    
'

Public Class ${Entity.Name} 

'    Private Fields

<#
for each Property in Entity.Properties
    message    "Procesando Campo ${Property.Name}"
#>
    Private m${Property.Name} as ${VbType(Property)}
<#
end for
#> 

'    Default Constructor

    Public Sub New()
    End Sub 

'    Public Properties

<#
for each Property in Entity.Properties
    message    "Procesando Propiedad ${Property.Name}"
#>
    Public Property ${Property.Name}() as ${VbType(Property)}
        Get
            Return m${Property.Name}
        End Get
        Set(ByVal Value As ${VbType(Property)})
            m${Property.Name} = Value
        End Set
    End Property
<#
end for
#> 

End Class 

Like before, control structures are used. XML is the serialized format of the model. During the code generation process, the model is loaded in memory, ready to be accesible via dynamic variables.

The steps

We have more files to generate: from the pages ASPX, and their associated code, the projects of facade on watch, organizations, access to data, the file of solution, and more. In order to automate this generation, the example has several files of tasks, in the Tasks directory, where the steps are described to execute. There are two great tasks: the steps to execute independently of the chosen technology, like completing the model, reviewing it, and the employees of the technology, like generating such file JSP or ASPX, depending on if we want Java or .NET.

The task of completing the model is in charge of Tasks\BuildProject.ajg, that begins with:

'
' Build Project
'    Complete the Project Data
'    Project must be loaded in global variable Project
'

PrintLine "Completing Project ${Project.Name}" 

include "Templates/EntityFunctions.tpl"
include "Templates/Utilities.tpl" 

if not Project.Title then
    Project.Title = Project.Name
end if 

if not Project.Version then
    Project.Version = "1.0.*"
end if 

if not Project.SystemName then
    Project.SystemName = Project.Name
end if 

The template includes some auxiliary functions, and then, it begins to complete the model that resides in the Project variable. For example: if the project lacks Project.Title the program set Project.Name as Project.Title. The program continues:

for each Entity in Project.Model.Entities
    PrintLine "Entity " + Entity.Name 

    for each Property in Entity.Properties
        PrintLine "Property " & Property.Name
        if Property.Type="Id" and not Property.SqlType then
            Property.SqlType="int"
        end if
        if Property.SqlType and not Property.SqlColumn then
            Property.SqlColumn = Property.Name
        end if
        if Property.Type="Id" and not Entity.IdProperty then
            Entity.IdProperty = Property
        end if
        if Property.Reference then
...

After that process, the technology tasks are executed. The example use Tasks\BuildVbNet2.ajg, here a fragment:

<# 

include "Templates/Utilities.tpl"
include "Templates/VbNet2/UtilitiesVb.tpl" 

message "Creating Directories..." 

FileManager.CreateDirectory(Project.BuildDir)
FileManager.CreateDirectory("${Project.BuildDir}/Sql")
FileManager.CreateDirectory("${Project.BuildDir}/Src/${Project.Name}.Entities")
FileManager.CreateDirectory("${Project.BuildDir}/Src/${Project.Name}.Entities/My Project")
FileManager.CreateDirectory("${Project.BuildDir}/Src/${Project.Name}.Data")
FileManager.CreateDirectory("${Project.BuildDir}/Src/${Project.Name}.Data/My Project")
FileManager.CreateDirectory("${Project.BuildDir}/Src/${Project.Name}.Services")
FileManager.CreateDirectory("${Project.BuildDir}/Src/${Project.Name}.Services/My Project")
FileManager.CreateDirectory("${Project.BuildDir}/Src/${Project.Name}.Business")
FileManager.CreateDirectory("${Project.BuildDir}/Src/${Project.Name}.Business/My Project")
FileManager.CreateDirectory("${Project.BuildDir}/Src/${Project.Name}.WebClient")
FileManager.CreateDirectory("${Project.BuildDir}/Src/${Project.Name}.WebClient/App_Themes")
FileManager.CreateDirectory("${Project.BuildDir}/Src/${Project.Name}.WebClient/App_Themes/Default")
FileManager.CreateDirectory("${Project.BuildDir}/Src/${Project.Name}.WebClient/Admin")
FileManager.CreateDirectory("${Project.BuildDir}/Src/${Project.Name}.WebClient/Controls")
FileManager.CreateDirectory("${Project.BuildDir}/Src/${Project.Name}.WebClient/MasterPages")
FileManager.CreateDirectory("${Project.BuildDir}/Src/${Project.Name}.WebServices")
FileManager.CreateDirectory("${Project.BuildDir}/Src/${Project.Name}.RemoteServices") 

message "Defining Solution and Projects..." 

...

In this fragment, the directories necessary are created to lodge the solution. The name of the directory is extracted of the model from Project.BuildDir. Note that ${ } in a string is used to expand the inside expression into the string value.

Technology Model

Under the directory Project\AjFirstExample\Technologies they are some models that describes the technology parameters to use:

 

Let’s examine VbNet2.xml:

<Technology>
    <Programming>
        <Dialect>VbNet2</Dialect>
    </Programming>
    <Database>
        <Dialect>MsSql</Dialect>
        <Name>AjFirstExample</Name>
        <Username>sa</Username>
        <Prefix>ajfe_</Prefix>
        <Host>(local)</Host>
    </Database>
</Technology>

These data is used during the template generation phase. It indicates the language, and the database to use.

Generating the solution

We could send the tasks from the command line, but we have a .build file for Nant, one for each technology to generate. We execute the tasks build, buildsql, and deploysql of AjFirstExampleVbNet2.build with the command line:

nant -buildfile:AjFirstExampleVbNet2.build build buildsql

(You must adjust the line

<property name=”ajgenesis.dir” value=”…./AjGenesis-0.5″/>

to reflect your AjGenesis installation directory)

Note the following lines in the build file:

    <target name="loadtasks" description="loads AjGenesis tasks">
        <loadtasks assembly="${nanttasks.dir}/AjGenesis.NAnt.dll" />
    </target> 

    <target name="init" depends="loadtasks" description="init the AjGenesis model, create build directory">
        <mkdir dir="${build.dir}"/>
        <loadmodel model="${project.dir}/Project.xml"/>
        <loadmodel model="${project.dir}/Technologies/${technology}.xml"/>
        <executetask task="${tasks.dir}/BuildProject.ajg"/>
        <executetask task="${tasks.dir}/BuildTechnology.ajg"/>
    </target> 

These tasks load an AjGenesis NAnt tasks, load the models, and execute the tasks.

In the Build/AjFirstExample/VbNet2/Sql directory they are left scripts of creation of the base and stored procedures. And in the directory Src brother, surprise! We’ll have the generated solution:

There were generated several projects, into a solution. We can load the solution into the Visual Studio 2005:

Using another NAnt file, AjFirstExampleCSharp2.build, we can generate the same solution in CSharp:

You will find other projects and examples of .build files, that generate solutions using NHibernate, Hibernate use, JSP, and concepts of Domain-Driven Desing a la Eric Evans.

Reflections

Sure, everything cannot be generated automatically. It is important to remember always that fact. But in the day to day, we recognize that we have amount of repetitive text, tasks that we can well delegate to software.

A key point: the model in AjGenesis is free. The presented examples are only examples: we can general the model that we want, and to write the templates we need. It is important to write the templates so that the generated code is similar to what we had manually generated. If we don’t feel comfortable with the generated code, if it does not have our style, our experience, we’ll end up generating something that we do not understand.

Another thinking: the model must be independent of the technology. In the final example, we have seen how, from the same model, we can generate solutions for VB.NET, CSharp and other technologies.

Software can help us to generate software. More: it MUST help us. Our experience counts: what we learned to make applications, we can overturn it in this species of expert system, code generation tools. In the future, I hope to be able to incorporate to the project, in the templates and tasks, more decision making: as well as we gain experience in writing of applications, we can incorporate our accumulated knowledge on patterns, architecture and styles of programming.

And as it is an open source project, AjGenesis allows us extend it, to our taste and necessity.

Suggestions, use case stories, comments are welcome. You can write as comments to this post, or write directly to me. Thanks to all that tested and adopted this project, and helped me to write it.

Angel “Java” Lopez
http://www.ajlopez.com/en

October 2, 2007

What’s new in Visual Basic.NET (Part 2)

Filed under: .NET, Programming Languages, Visual Basic .NET — ajlopez @ 10:01 am

I wrote about some new features in the new version of VB.NET 9, that is integrated inside the Visual Studio 2008. I’m working with the Beta 2. You can read:

What’s new in Visual Basic .NET (Part 1)

For this post, I wrote an example, that can be downloaded from VbNetNew2.zip

As in the previous example, I’m using a class Supplier. In a module named Extensions, I put two new extension methods:

Imports System.Runtime.CompilerServices 

Module Extensions 

    <Extension()> _ 
    Public Function Append(Of T)(ByVal a As T(), _
ByVal b As T()) As List(Of T) 
        Dim result = New List(Of T)(a) 

        result.AddRange(b) 

        Return result 
    End Function 

    <Extension()> _ 
    Public Sub Show(ByVal suppliers As IEnumerable(Of Supplier)) 
        For Each supplier As Supplier In suppliers 
            Console.WriteLine("Supplier {0} {1} ({2})", _
supplier.SupplierId, supplier.Name, supplier.City) 
        Next 
    End Sub 

End Module 

Remember: extension methods can be attached to instances of existing classes, extending it functionality. This is a new feature, that can be used to enhance the behaviour of any framework class. LINQ is an example of extension methods: it adds many new functions to list, collections, dictionaries, without the need of change the framework.

In VB.NET, extension methods are defined as methods inside a module, and they are marked with the attribute <Extension()> . The type of the first parameter is the class to be extended.

The above Append method, uses generics. It’s a method to be applied to any array, of any given type T. And it returns a typed list of T items.

The Show method is used in any IEnumerable of Supplier elements.

This is an example of the flexibility of extension methods. Really, it is a powerful way to change and enhance any class, type, and generic type.

In the Main method, the Append is used to obtain the union of two list, and then, the Show method prints the resulting list:

 1     Sub Main() 
 2         Dim suppliers() As Supplier = New Supplier() { _ 
 3             New Supplier(1) With {
.Name = "John Madison", .City = "Washington"}, _ 
 4             New Supplier(2) With {
.Name = "Ann Arbor", .City = "Ohio"}, _ 
 5             New Supplier(3) With {
.Name = "Don Johnson", .City = "Miami"}, _ 
 6             New Supplier(4) With {
.Name = "Bill Clinton", .City = "Washington"} _ 
 7         } 
 8  
 9         Dim suppliers2() As Supplier = New Supplier() { _ 
10             New Supplier(5) With {
.Name = "John Smith", .City = "New Jersey"}, _ 
11             New Supplier(6) With {
.Name = "Mary Dupinsky", .City = "Los Angeles"}, _ 
12             New Supplier(7) With {
.Name = "Ronald Reagan", .City = "Washington"}, _ 
13             New Supplier(8) With {
.Name = "Brad Shapiro", .City = "Dallas"} _ 
14         } 
15  
16         Dim allsuppliers = suppliers.Append(suppliers2) 
17  
18         Console.WriteLine("All Suppliers") 
19         allsuppliers.Show() 
20  
21         Dim suppliers3 = allsuppliers.FindAll(
Function(s) s.City = "Washington") 
22  
23         Console.WriteLine() 
24         Console.WriteLine("Suppliers In Washington") 
25  
26         suppliers3.Show() 
27  
28         Dim suppliers4 = From s In suppliers _ 
29                              Where s.City = "Washington" _ 
30                              Select s 
31  
32         Console.WriteLine() 
33         Console.WriteLine("Suppliers In Washington") 
34  
35         suppliers4.Show() 
36  
37         Console.ReadLine() 
38     End Sub 
39 

At line 21, an extension method from LINQ is applied to find any element in the list that satisfies a predicate. This predicate can be defined inline, as an anonymous method, with the new keyword Function.

At line 28, LINQ is used directly in the language. As in C Sharp, the  from is written before the select. This “strange” order  is used by the IDE to determine what kind of data is selected, information that it infers with the from clause.

Angel “Java” Lopez
http://www.ajlopez.com/en

October 1, 2007

What’s new in Visual Basic .NET (Part 1)

Filed under: .NET, Programming Languages, Visual Basic .NET — ajlopez @ 9:29 am

In previous posts:

What’s new in C Sharp (Part 2)
What’s new in C Sharp (Part 1)

I wrote about some new features in C Sharp 3, integrated in Visual Studio 2008 (I’m using the Bete 2).

Now, I have an example, in VB.NET 9 (the new version of the language), to download from VbNetNew1.zip

It’s a simple console application, that has a class Supplier:

Public Class Supplier 
    Private mSupplierId As Integer 
    Private mName As String 
    Private mCity As String   

    Public Sub New(ByVal id As Integer) 
        mSupplierId = id 
    End Sub   

    Public Property SupplierId() As Integer 
        Get 
            Return mSupplierId 
        End Get 
        Set(ByVal value As Integer) 
            mSupplierId = value 
        End Set 
    End Property   

    Public Property Name() As String 
        Get 
            Return mName 
        End Get 
        Set(ByVal value As String) 
            mName = value 
        End Set 
    End Property   

    Public Property City() As String 
        Get 
            Return mCity 
        End Get 
        Set(ByVal value As String) 
            mCity = value 
        End Set 
    End Property 
End Class 

I didn’t found any support in the new VB.NET for automatic properties, as in C Sharp. So, in this example, the class code has no new feature.

At subroutine Main:

 1     Sub Main() 
 2         Dim suppliers() As Supplier = New Supplier() { _ 
 3             New Supplier(1) With {.Name = "John Madison",   
.City = "Washington"}, _ 
 4             New Supplier(2) With {.Name = "Ann Arbor", 
.City = "Ohio"}, _ 
 5             New Supplier(3) With {.Name = "Don Johnson", 
.City = "Miami"} _ 
 6         } 
 7  
 8         For Each supplier As Supplier In suppliers 
 9             Console.WriteLine("{0} {1}", 
supplier.SupplierId, supplier.Name) 
10         Next 
11  
12         Dim c = New With {.Name = "John Doe",   

.City = "Everywhere"} 
13  
14         Console.WriteLine("{0} lives in {1}", c.Name, c.City) 
15  
16         For Each supplier As Supplier In suppliers 
17             supplier.Print() 
18         Next 
19  
20         Console.ReadLine() 
21     End Sub 
22 

there are some new features in use. At line 2, you see the creation and initialization of an array, using brackets. At lines 3, 4, and five, the creation of objects uses With. Using this word, we can call a constructar, as Supplier(1), and then complete the properties, using point and the property name.

At line 12, a variable is created with an implicit type. The new doesn’t refer to any class, but using with the properties can be defined.

Then, IDE “makes”, infers the type of variable c, and we can use  c.Name and c.City as at line 14.

At line 17, Print is not a method of class Supplier. It’s defined in other “class”:

Imports System.Runtime.CompilerServices   

Module Extensions   

    <Extension()> _ 
    Public Sub Print(ByVal supplier As Supplier) 
        Console.WriteLine("Supplier {0} {1}", _ 
supplier.SupplierId, supplier.Name) 
    End Sub   

End Module 

This is an extension method: a method that can be defined to all instances of a class, out of this class definition. In CSharp, we use static classes to this purpose. Here, in VB.NET, we use modules. To be an extension method, in CSharp a this is used in the first argument. Here, an attribute <Extension()> is attached to the method definition. That attribute is defined inside namespace System.Runtime.CompilerServices.

Angel “Java” Lopez
http://www.ajlopez.com/

Create a free website or blog at WordPress.com.