WebLink > Introduction

WebLink is a demo application that illustrates using Dimeric Server Pages (DSP) and Virtual Database (VDB). The source code to WebLink ships with DSP.

--> To run the application, start at the topic list.

What WebLink Does

WebLink is a simple web application that manages a database of links (URLs). Links are organized into categories, for example, "Cooking", "Programming", "Sports", etc. WebLink allows the user to view, create, edit, and delete categories and links. The data is kept in a InterBase database (which also ships with DSP). WebLink uses VDB for its data access (employing either IBX or BDE, as specified in the WebLink.ini file).

WebLink in Detail

This section discusses various techniques employed by WebLink.

Header and Footer Pages

Every page in the WebLink application ends with the same boiler-plate text. This is easily accomplished with the <%@ run script="SomeFile.dsp" %> directive. First, we create a DSP page for the footer, called Footer.dsp. In this page, we place the boiler-plate text that will appear at the end of each web page. Next, as we define new web pages, we will insert a <%@ run script="Footer.dsp" %> directive at the bottom of each page. Behind the scenes, Footer.dsp is compiled into a procedure (specifically, a procedure that writes HTML text to an output stream). Each of the web pages that contain the above run directive will call this procedure. DSP also offers the <%@ include SomeFile.dsi %> directive, which includes the contents of one file into another at compile time (more info). WebLink also employs a header, named Header.dsp.

The run directive has many other uses. For example, it is helpful in making navigation menus that appear on multiple pages. You can even pass arguments to the called page (more info).

Database Access

VDB is the ideal data access layer for a DSP application. Of course, any data access library may be used in a DSP application, but WebLink uses VDB (and takes advantage of many of VDB's benefits).

There are numerous pages in WebLink that need access to the database. By using the include and run directives, we can ensure that the individual pages are easy to develop and maintain. We wish to centralize how the database connection is obtained, so that this code is not repeated in every web page. WebLink includes a regular Delphi unit named Database.pas, which defines two functions related to the database:

  function GetDatabase: IDatabase;
  function GetSerialColUtil: ISerialColUtil;
Of course, if a web page wishes to call GetDatabase, then it needs to use the Database.pas unit. In DSP, this is accomplished with the <%@ uses SomeUnit %> directive (more info). The GetDatabase function obtains a new connection, possibly from VDB's connection pool. In theory, this is all we need, but in practice it leaves something to be desired.

In any substantial web page, we will be executing more than one query, possibly with transaction control. Therefore, we need to use the same database connection during the entire web page. Obviously, we can just call GetDatabase and keep the result in a local variable. When the web page completes, this variable will go out of scope (thus the connection will be returned to the connection pool). To make the individual web pages even simpler, we will define a local function named Database that will return the database connection. The first time a web page calls this function, a new connection is obtained using GetDatabase. This result is stored in a special local variable (never referenced directly in the web page) so that Database can return the same object when it is invoked subsequently.

All of the above functionality is needed on any web page that accesses the database, so WebLink consolidates this into a single include file: Database.dsi...

  <%@ options errorPage="ErrorPage.dsp" %>

  <%@ uses DB, VirtualDB, Database, VDBSerialColUtil %>

  <%@ begin nested %>
  <%
  var
    _Database: IDatabase;

  function Database: IDatabase;
  begin
    if not Assigned(_Database) then
      _Database := GetDatabase;
    Result := _Database;
  end;
  %>
  <%@ end nested %>
The first line is an error page directive that establishes ErrorPage.dsp as the handler for any uncaught exceptions (more info). The next line ensures that various units are available to the web pages. The remainder of the file is a nested section, which places code into the nested scope of the procedure that generates the web page (more info). The nested block defines two things: the _Database variable, and the Database function. As you can see, Database sets _Database the first time it is called, reusing this value on subsequent invocations. Because this code is in the nested section, any variables declared here are not global -- they are local. This is important for two reasons: the variables are thread-safe; and the lifetime of the variables is that of the web page.

Database Access - Example

Now that we have defined Database.dsi and Database.pas, we can make a web page that accesses the database. For example, TopicList.dsp displays all topics in the database...

  <%@ include Database.dsi %>
  <%@ begin nested %>
  <%
  var
    TopicQuery: IQuery;
    TopicID: Integer;
    Name, Descr: string;
  %>
  <%@ end nested %>
  ...
  <%
    TopicQuery := Database.RunQuery(
      'select * from topic order by name');
    while not TopicQuery.Eof do begin
      TopicID := TopicQuery['topic_id'];
      Name := TopicQuery['name'];
      Descr := TopicQuery['descr'];
      // ...
      TopicQuery.Next;
    end;
  %>
  ...
As the above listing illustrates, a web page simply uses the Database function for data access. For pages that make changes to the database, the transaction control methods (PushTrans, PopCommit, and PopRollback) would be recommended. See EditTopic.dsp for an example.

Error Pages

All pages in WebLink specify an error-handling page: <%@ options errorPage="ErrorPage.dsp" %>. This indicates that ErrorPage.dsp should be executed in the event of an unhandled exception. This page displays the exception's message, along with some (potentially) useful information, such as a technical support contact. This feature of DSP allows applications to centralize their error-handling. If a page does not specify an error handler, then the user will see the all-too-common "Internal Server Error" message in their browser.

Redirecting After Updating

In WebLink, any page that updates the database redirects the browser to a different page (after making the updates, of course). This is important because it allows the user to hit the browser's Refresh button at any time. For example, PostTopic.dsp inserts or updates a row in the TOPIC table. Before completing, it redirects the browser to TopicList.dsp as follows...

  Response.SendRedirect('TopicList.dsp');
Sometimes the target of the redirect requires parameters, as in the case of PostLink.dsp. It redirects to ViewTopic.dsp, which requires an id parameter...
  Response.SendRedirect('ViewTopic.dsp?id=' + IntToStr(TopicID));
You can find out more about Response, and other related objects, in the documentation that ships with DSP. This is also available online.



WebLink (sample DSP & VDB app.) © 2002 Copyright 2002, Dimeric L.L.C. Dimeric Software