A case study for ECO II: An ASP.NET web site

By: Peter Morris

Abstract: This article outlines Peter's experiences of rewriting www.HowToDoThings.com using ECO

Background

www.HowToDoThings.com was written back in 2001 as an experiment when I first discovered that classic ASP has OOP support. Unfortunately OOP support in classic ASP is very poor and I was very disappointed. However, I decided it might be a good idea to transfer my collection of Delphi tips from the Delphi tips folder on my hard drive to somewhere remote, so that I had somewhere safe to keep them and also so that I could refer others to them.

As time went by my complete lack of interest in ASP development started to show, and the quality of the website started to suffer. Id know for some time that a redevelopment was needed, but had no incentive.

Finally in 2004, with the release of ECO II I had an incentive. Its really quite a coincidence that the urge to rewrite the website again came from wanting to develop using OOP, but this time the whole website would be object driven.

The challenge  A model driven website

Having developed applications in Bold for Delphi since 2001 I already knew the power of Model Driven Architecture. With the release of ECO II for the .net framework I was practically itching to find a project to develop with it.

One of the first things I wanted to change about the structure of the original website was the categorisation of articles. The original categorisation was structured like this:

Topic Category SubCategory
Computers Programming Delphi
Computers Programming Java
Etc Etc Etc

Although this structure seemed suitable at first it quickly became apparent that it was not flexible enough. Sometimes it would have been nice to be able to sub-categorize Delphi articles into groups such as Graphics, ActiveX, or ISAPI. The new website would need a much more flexible implementation.

It was so tedious to develop new pages in classic ASP that I never did get around to creating any administration pages. Administration was performed by entering SQL statements into a HTML <input> on a page named Control.asp, it was not very user friendly and also prone to error. The next thing I wanted to achieve was a set of administration pages.

The implementation

I created my business objects inside an ECO package in a dll project. It always makes sense to separate your business logic from your presentation layer and this approach made it possible to take this technique to the next step, making the business logic a completely separate binary file which may be used from various types of GUI applications. After spending many years learning to love ModelMaker I decided to use ECO Modeler to create the business objects instead of Together. Please keep in mind the fact that Together is not ECO, it just creates ECO models.

The model

Tackling the first requirement of the project I decided to allow a potentially unlimited number of sub-categorisation for articles. To achieve this I used the following approach:

Categories UML diagram
  1. BaseCategory  An abstract base class. This was modeled into the business layer to enable the parent of a SubCategory to be either a MainCategory or another Subcategory, a simple composite pattern.
  2. MainCategory  These are the items which appear on the main page, they may hold child categories but not articles.
  3. SubCategory  These classes may hold child SubCategories, and optionally allow the addition of articles.

Using this technique I was able to achieve the Yahoo.com approach and allow as many levels of categorization as desire. It also provided the extra benefit of enabling me to easily implement a recursive OCL statement to show the category path of the current article.

I added a derived string attribute to SubCategory like so:

Name Path
Expression parentCategory.path + ' / ' + name

Accessing the Path attribute of a SubCategory would return the Path of its parent concatenated with its own name. The parent category would do the same, all the way up to the top level, where the MainCategory would simply return name as the result.

Not a single line of code was written to accomplish this fairly complicated feature.

Object identities

After passing around ECO object Ids as url parameters for a while I noticed something peculiar. An object id the last time I ran the website appeared as something like 7:12, but after modify the model and regenerating I noticed it had changed to something like 8:12.

At first I thought that something was wrong. Further investigation revealed that the result of IdForObject is not very static. When an ECO application starts one of the first things that happens is the process of creating an in-memory representation of the model using reflection. Each class within the model is sorted into some kind of hierarchical order. The structure to an ECO ExternalId is as follows

<ClassIndex> : <ObjectId>

Although the ObjectId of the object will never change, it is very likely that the class index will change as you restructure your model over time. At face value this could easily be considered to be acceptable, but seeing as many of my website hits come from people searching in Google it was imperative that the urls remain as static as possible.

Bryan Crotaz suggested that I should model my own ID into the model. One of my rules whenever developing RDBMS applications was Never use meaningful data as part of your primary key, it just hadnt occurred to me that this is exactly what I was doing until Bryan pointed it out to me.

The solution to this was to introduce a root class to my model and add a GUID attribute named UniqueId. I then ensured that every object ultimately descended from this class. I could then quite easily implement a GetObjectByUniqueId method in my EcoSpace and retrieve any object by a static, unique identifier.

EcoSpace pooling

For efficiency purposes ECO web applications retrieve EcoSpaces (a cache of in-memory objects) from a pool of pre-created instances. One of the things I noticed about the default template for an ECO asp .net WebForm was that an EcoSpace is retrieved from the pool each time a page was generated. Most of the time when altering articles, maintaining the site categories etc there is no need for an EcoSpace. Typically the page will fetch an object only once, validate user input during multiple postbacks, and then finally update the database with the changes.

The first thing I would do in any new page would be to make sure that EcoSpace.Active was only set if the page was not a PostBack. Note that it is possible to edit the standard ECO asp .net WebForm template by editing it in the DelphiSource folder.

EcoSpaces are also not allowed to be returned to the pool if they are dirty (have modified objects in them). An EcoSpace may be held in the users Session object in such circumstances, but I opted not to allow this at all. It occurred to me that if I only have ten EcoSpaces in my pool, and ten people are returning dirty EcoSpaces, they would quickly disappear into Session variables and disappear from the pool.

I decided to check each EcoSpace upon return to the pool and throw an exception if it was dirty. This would help me to ensure that I never deprived the pool of an EcoSpace at the end of a page request.

WebForm development

WebForm development was nowhere near as tedious as with classic ASP. This was obviously due partly to the improvements in ASP . net, but was also much more pleasurable for the fact that I was working only with OOP. Saving an object would involve the following steps:

  1. Fetch an EcoSpace from the pool.
  2. Start an in-memory transaction.
  3. Create a new object (or fetch the existing object).
  4. Populate the updates to the objects attributes from the web controls.
  5. Validate the object based on the modeled constraints.
  6. Either rollback the transaction or update the database depending on whether or not any of the constraints are broken.

Adding validation to the model was a liberating experience. Being able to specify a list of OCL expressions to a class which indicate the validity of the object, and then having the GUI evaluate the broken constraints was a real time saver. Any time the rules of the business object changed all I needed to do was to recompile and redistribute the DLL containing the model, no GUI updates were needed at all.

Seeing as the creation of WebForms was so simple I decided to add a selection of administration pages. Modify articles, delete articles, suspend users logins, move articles to new categories, add new categories, reorganize categories, etc. No more SQL statements in a HTML <input> at last!

Deploying the website

Id love to tell you that this whole learning experience was painless, but it was far from it. Luckily though this was due entirely to my complete ignorance regarding SQL Server administration. Luckily I have a friend who is a system administrator, and he spent quite some time helping me out. Here are the lessons I learned from the experience, which I will pass on in order to save you the agony:

Lesson 1: Use the sa account when generating your database.

I used HowToDoThings as my username for connect o the database at design time when generating my database schema. Unfortunately this meant that when I deployed the application to the server all of my tables were named like so

HowToDoThings.Article
HowToDoThings.Author

instead of the usual

dbo.Article
dbo.Author

This may not look like much of a problem, expect that none of the SQL statements generated by ECO would run. SQL Server was now expecting SQL such as Select * from HowToDoThings.Article, which of course ECO wasnt creating.

I would recommend having the sa username/password in the database connection string for creating/updating the DB schema at design time, but reading the connection string from web.config at runtime.

Lesson 2: Dont give your user the same name as your database.

I had now recreated my database so that the tables were named correctly, and needed to give my HowToDoThings user permission to use the HowToDoThings database. Every time I tried this I received an error Object HowToDoThings already exists. Using a different name for the DB and the user worked perfectly.

Conclusion

In total Id guess it took me about fourteen days to convert my old website over (not including time spent on graphics etc). I didnt attack it with raw determination, I just spent a little time on it now and again whenever I have five minutes to spare. I also tried various approaches before deciding to scrap them and start again, so there was also a lot of discarded work.

I must say that developing a website with ECO was eventually very simple. After recently developing a site using the standard MS recommended 3-tier approach

  1. Web site.
  2. Data access classes.
  3. Stored procedures / DB.

I decided that although ECO initially takes a little longer to learn that the recommended approach, it has none of that really boring repetitive work that makes you want to give up your career as a programmer.

I eventually managed to rewrite the entire website, meet all of my goals, and all this without writing a single line of SQL. I found that web development with ECO was a very productive experience, and will certainly be utilizing it in all of my future data driven websites.

Tools used for this project
Delphi 2005 Architect http://www.borland.com/delphi
ECO Modeler http://www.modelmakertools.com/eco-modeler.htm
SQL Server http://www.microsoft.com/sqlserver

Server Response from: ETNASC03