Wednesday, May 31, 2006

The specifications for my latest project have been daunting. The application is a web-friendly version of an existing training record manager, which interfaces with the web-based training we produce and sell. The previous incarnation of the manager is the better part of a decade old, and written in Access 2 Basic. It runs locally, obviously, so one of the immediate advantages of a web-based version is that it would not require installation on each of 30 machines at a site (for instance), and also that this could be hosted locally.

The snag is this: many existing clients are running the existing system with a database networked off a file-server; others have invested in a dedicated web-server, while still others would like to host off our web-server. A previous incarnation of our system, responsible for running training and storing the results, but providing no additional record management or reporting functionality, is implemented as two systems ganged together. Web-server users are provided a server-side ASP application, while file-server users use similar functionality implemented in client-side script. Whereas the majority of the database layer is shared between the two, the presentation layer is duplicated.

This makes for a difficult to maintain code-base.

The solution which was implemented for the training record system was to take advantage of the XSL/T engine, which can run on both server- and client-side. This allows the same presentation layer to be used for both flavors of the application. Changes to the presentation layer are made by changing the presentation XSL.

In order to accomplish this, database access is encapsulated in a JavaScript library. To display a page, the database library returns an XML stream, which is transformed by the appropriate XSL in the presentation layer. The resulting HTML is written to the page. Both flavors of the application also share an active layer, which responds to control events on the client-side.

When this mechanism is wrapped up in a few appropriate classes in a shared library, the actual page code becomes quite simple:
ListEditor.htm








ListEditor.asp



<%

ProcessFormParameters()
InitializeLibrary()
ExtendLibrary()

With objPage
.selfreference = "frm_ListEditor.asp"
.selfrefshort = "ListEditor"
.ProcessFormState()
.CreateFormContent()
.XSLPath = Server.MapPath(objPage.XSLPath)
.addXML(objClientAuthentication.getClientSpecificXML())
.addXML(objUserAuthentication.getClientXML())
.addXML(objUserAuthentication.getLoginXML())
Response.write .createPage()
End With

%>



A very clear separation is maintained between data and presentation, and between client and server. I was quite happy the day I discovered you can use “runat” in a script tag to make a library available to a server-side application. You can also see in the above code how Client and User authentication data have been added to the XML stream for the web-server flavor of the application, and not the file-server. This is by design, since the file-server application requires a lower level of authentication. In this way, the processing layer in between data and presentation can contain any processing code that is required for one flavor but not the other.

The processing layer consists of a main library, which contains the Page class, which gets extended by an extension script. When the library gets extended, it gains two new methods, processFormState and createFormContent, which provide logic for navigating from page to page and the XSL to use for a selected page. Each major section of the application has its own extension script. To change the navigation between pages, you only need to make a change to the appropriate extension script.

Implementing the application this way initially took some extra effort, but as development continues, new additions are easier to make.

A note on AJAX: obviously, you can’t target an AJAX application to both file- and web-server; however, when you package your entire presentation layer into XSL stylesheets, and interesting thing happens. First, you realize that all of your pages share an assortment of common paraphernalia, like html headers, form-centering tables and, and navigation buttons. Second, you move all of the content into a separate XSL stylesheet. Third, well, then you start thinking about the content that is left behind.

What you are left with is the active content on the page, and transforming your stylesheet so you can generate only this content is quite straightforward, if you are so inclined. If you update only this content on the page, using asynchronous server requests, you get cleaner page transitions. Just sayin’, though, you wouldn’t get many of the benefits of a full-blown AJAX application, like increased interactivity and lightning-fast page updates when you want to just reload one textbox on the page.

For instance: