Component Software for Business
Total Page:16
File Type:pdf, Size:1020Kb
Database Development for the World-Wide-Web
Introduction
The Internet is a well-established fact of life, and while a lot of the Internet’s content comes in the form of ‘static’ web pages composed of text files in HTML format and images, our interest is in the methods that we can use to publish data from database tables on web pages. Web sites that derive their content from database files are often referred to as ‘dynamic’ web sites because if any of the data in the source database is changed (new data added, existing data deleted or updated), the next person to access the web site will see these changes immediately. Dynamic web sites are created by producing programs or scripts that generate the web pages on demand. While this may initially seem like a very wasteful use of computer processing power since there may be long periods during which the data does not change and yet the web server continues to slavishly re-generate web pages that it has generated many times before, the process of publishing this ‘live’ data on the web is only marginally less efficient that that required to copy existing files of HTML text stored on a disk. In these tutorials, you will discover the basic mechanisms for creating dynamic web sites and by following the included practical sessions, you will gain practice in the techniques necessary to implement dynamic, data-driven web sites.
Practical Issues
If you intend to follow the practical sessions throughout these tutorials, you will need only a few tools to allow you to do so. The first and most important tool is a Web Server: don’t panic, this does not mean you need to go out a purchase a big, industrial strength computer and start negotiating with an Internet Service Provider to provide you with a T2 connection to the Internet. In fact, web servers tend to come free with many computer operating systems, and operate perfectly well for executing web pages with active content for delivery to a browser on the local machine. If you have a computer with a copy of Windows 98, Millennium, 2000 or XP, you will almost certainly have the software necessary to set up a web server. For the practical exercises described here, you won’t even need an internet connection. If you have Windows 95, you can download a copy of Personal Web Server from the Microsoft web site (although of course you do need a connection to the web to do this). If you are running a computer installed with Linux, or an Apple Macintosh, you will also have web server software either already installed or easily available, although it is most likely that the practical sessions described here will not be compatible with your specific system – you will have to access one of the web-sites specific to your own computers, operating systems and web servers to find similar support material.
Web Sites and Web Pages
The Request-Response structure
A Website is a collection of files stored on a computer that is connected to the Internet and organised in a way that allows them to be accessed by any other computer that is connected to the internet and running a Web Browser. The World-wide-web was invented by Tim Berners-Lee, a physicist at Cern, the international atomic research facility located near Geneva in Switzerland. It was devised as a way for computers connected to the Internet to share documents easily, and is based on the idea of Hypertext – textual documents which are interlinked by a system of document references within them. Berners-Lee devised the Hyper-Text Transport Protocol (HTTP) and the Hyper-Text Mark-up Language (HTML) that became the core format for every website. HTTP is a simple system which is understood by web servers. When a request for a document arrives at a web server, the server responds by sending the document back to the address that issued the request – a very simple client-server arrangement not unlike the way database servers respond to SQL. From the client end, the request incorporates the address of the web server and the name and location (actually, a virtual location) of the document on the server. When this request is issued, a large database distributed across the internet (the Domain Name Service or DNS) is used to work out the actual Internet address of the server (a numeric address that locates it uniquely among all of the networked computers in the world) and the request is directed there. Request
Response
Web Browser Web Server Figure 1: Request-Response. The Internet Address of a web page or media file is issued at a browser and received by the web server. The HTML text of the web page is returned to the browser. Typically, the request comes from a Web Browser running on some computer, and is for a specific web page or resource, for example, www.BigBusiness.com/Documents/SomeDocument.html. In this case, the DNS would look up the Internet address for www.BigBusiness.com and pass the request for Documents/SomeDocument.html to it. The very clever part (alluded to by the word Hypertext in the acronym HTML) is that the document can contain text marked up in a special format understood by web browsers, and in particular, is likely to contain the addresses for other web pages. In this way, web pages contain links to other web pages, which may also contain links to other web pages and so on. The world-wide- web is a hugely interconnected network of web pages that refer to each other. This request-response organisation makes it trivially easy to create a web site by simply taking a bunch of documents and embedding inter-links within them at strategic points – a simple example is where index document contains a list of hyper- links to other pages on the site, and these pages contain links back to the index. An easy extension to this is that most web browsers can now display graphical content, and a web page can contain hyper-links to graphics files using the same request-response mechanism. In fact, a current web browser can cope with a large range of different types of content including audio, animations and video, all retrieved by the same request-response method. Static Pages, Server-Side Scripting and Client-Side Scripting
Using simply HTML text files and a smattering of other types of file containing graphics or other information, it is easy to build a ‘static’ website that will provide access to information about you, your hobby or your business. The down side of this is that as the details you wish to display change (obvious fundamental things like your age, which changes annually, or the products your company sells, which may change on a daily or weekly basis), so you need to maintain the files that make up the website to make the information up to date. The way around this is to create your website as a dynamic entity; one in which the information published can be updated automatically because the source material is kept up to date not by you altering the text that makes up the web pages, but by changes made to the source of the material. For example, if you were to display your age on a web page by simply putting a number in the HTML text, this will never change and so you will need to manually change the HTML text every year to keep it accurate. If however, you published your age by having it automatically worked out from your date of birth and the current date (something that is made available by just about every computer operating system), then it will always be correct and you will never need to update the page. If you published your company’s list of products not by simply listing them in a HTML file, but by extracting the product data from your company’s inventory database and sending this data back with some formatting to the browser, again the page will always be up to date (or, at least, as up to date as the source database). This type of publishing, known as server-side scripting, is done by embedding instructions into the web pages stored on the server to calculate or extract the necessary information and format it as necessary before sending it on to the client browser that issued the request. There is a growing variety of ways in which this can be done – programs can be written to generate HTML from data extracted by a database and connected to the web server, usually by placing them is a special directory on the server that is used to host these CGI (Command Gateway Interface) programs. Alternatively special ‘script’ statements can be embedded in web pages that are executed by the web server as it processes the request for the page. The generic name for the second method is Active Server Pages, and describes the general mechanism where the web server is configured to interpret scripted instructions embedded in web pages. Active Server Pages can be written in a variety of languages that can be ‘plugged-in’ to a web server; e.g. JavaScript, PHP, Python and VBScript. We will use the latter in the practical sessions, since this language is similar to the Macro language used in Microsoft Access, and is the standard scripting language for Microsoft web servers.
Active Server Page
The Internet Response
Database Request
Web Server
Figure 2: Active Server pages can generate a ‘live’ response to a web page request Script can also be created to execute in the client’s browser. This client-side script is an efficient way of doing some of the work, but has limitations that make it not particularly useful for our purposes. For a start, you can not publish data from a database that you host on the server by executing a script on the client’s computer; apart from it being an absurd idea (the database is at your end of an internet connection – not the client’s), the browser would not allow such a thing on the basis of security, your web server would need to have been set up to trust scripts run from an anonymous source (a security nightmare), and there would need to be software on either side of the connection capable of maintaining the direct access the client has to your database. For these and other reasons, client-side script is never used to do much more than alter the way that information is presented in the browser, ‘jazz-up’ interactions between the user and the page on the browser or validate information that the user is required to send to the server. Even then, we can never be sure that the browser accessing a web page is capable of allowing script to run, or that if the browser is capable of executing scripts, that the facility has not been disabled. All in all, client-side scripting is a non-starter for publishing data.
Generating a page from a web server
If we have a computer with a web-server running on it, for example Microsoft’s Internet Information Server (IIS), we can create a website by simply adding files that contains some HTML text to a directory that the web server is set up to ‘publish’. For example, the following simple file, placed in a folder that was configured to be published by the web server, would be enough to display a static message on a client’s browser:
Hello HTML
Listing 1: Hello.html – this is a static html file, which would simply be sent from the server unchanged. The text in listing 1 is HTML. Everything enclosed in angled brackets <> is treated by the web browser as ‘mark-up’, special code to indicate something to the browser. The only pieces of non-mark-up text in this listing are the page title (enclosed in…
). This would result in the following display on a web browser (Internet Explorer, or IE) running on any computer connected to the internet:Figure 3: The Output from Hello.html Note that the web address (shown above the page in IE’s address bar) is given as http://paddington/DreamHome/Hello.html. The Web Server is hosted on a PC that I call Paddington (it is a laptop and I carry it around in a small suitcase – you figure it out), and I have set up a website in it called DreamHome (after the example database in the book). The file was saved to the folder that this website is hosted in with the name Hello.html. Of course, this is a static web page. To make a dynamic page, we need to change two things. First, the page needs to be named with an ASP file extension instead of HTML, so that IIS recognises it as a file containing script that is to be executed, and the page also need to have some script embedded in it.
<%@ LANGUAGE = VBScript %>
Hello HTML: the time is <%=Time%>
Listing 2: Hello.asp – this page contains script code embedded in the html to generate ‘live’ resultsFigure 4: The output from LIting 2 – note the display of the time. The significant difference between listings 1 and 2 is that the code in listing 1 will always display the same information, while the code in listing 2 will display information that changes as the time changes. The script ‘tag’, <%=Time%>, indicates a function that will be executed by the server when the page is sent to the client – in this case, the function returns the current time-of-day. Any text in an ASP file that appears within the ‘script tags’, <% and %>, will be directed to the script engine of the server. Provided this text is valid ASP code (i.e. provided it is syntactically correct for the language named at the top of the page – VBScript in this case), the script engine will execute it.
Pages, sessions and applications
A file with an ASP extension will generate a single page of a web site. For a web site to display multiple hyperlinked pages there will need to be a collection of HTML and/or ASP files on the server (it is normal to mix HTML pages and ASP pages on the same site to mix static and dynamically generated pages). The full set of ASP pages is referred to as an ASP Application; all of these pages are designed to operate together to fulfil some specific business purpose. Within an ASP application, there can be some specially named pages – typically Global.asa and index.htm, which have a specific purpose for a web application. With a normally configured installation of IIS, index.htm is the page that someone who points their web browser to the site without giving a specific page name (e.g. http://paddington/DreamHome) would get to. Typically, this page is the home page of a site and should be the ‘welcome’ page, providing links to key pages in the web and acting as a top-level menu. Global.asa performs a different function. This page contains a number of blocks of script (subroutines) that will execute automatically when a website is in use, providing code that initializes (sets-up) the site when it is first accessed, closes down database connections or other housekeeping if it has not been accessed for a while, and sets up and manages sessions – sequences of page accesses from a user of the site.
HomePage.htm LogIn.htm Login.asp CheckCredit.asp
Index.htm
Global.asa Catalogue.asp PlaceOrder.asp ViewOrders.asp
Figure 5: A small active web site, with a mixture of static (htm) pages, acti9ve (asp) pages and application pages (index.htm and Global.asa). The pages link (arrows) to each other to provide navigation through the site and to organize necessary services (e.g. login and credit checking). An ASP-based site typically interacts with many users, effectively doing so concurrently so that at any one time, there may be many different users all currently interacting with any page within the site. The sequence of pages accessed by each user is regarded as a session, and it is useful to be able to track any one user through all of the pages that they visit, either to gather statistics on the use of the site, or simply to save users from having to repeatedly send the same information to the site from page to page.
Session state
Tracking users through a site brings up one problem that is central to the way that Active Server Page websites are designed. Each request for an ASP page will execute some script. In sequence these ASP pages may, for example, allow a user to log-in to the site (to provide them with personalized information, or simply to prevent unauthorized access to restricted facilities), allow them to browse through several pages, perhaps selecting products to add to a shopping cart, and then to continue to a check-out page where the sale can be completed by the user entering credit card and delivery details (see figure 5). The problem is simply that the web application has no ‘memory’ that goes beyond a single page, so there is no simple way to know what stage in a sequence a client is on. Good website design demands this, because there is no compulsion for a user who has, say, added some items to a shopping cart to complete the process by going through the checkout page, or even to stay at the same website. You might think that a way around this would be to keep track of the user as they browse from page to page of the site, gathering information as they go and keeping this information ready for when the next page request arrives. However, as designers of a website, we have no knowledge of, or way of controlling the number of simultaneous users of the site. A site could at any time have zero, 100 or 1000000 current visitors, and if the web server was required to actively track each of these, it could take up a lot of time and memory (or none). For the site to remain efficient regardless of how many current visitors there are, it is necessary for the server to NOT be aware of the sequence of page requests for each and every visitor. However, for it to keep track of the current stage that each visitor to the site is at, the website must have some way of retaining their current status. Well designed web-sites are built to be ‘stateless’ – that is, there is no specific storage of data between sequential visits to active server pages. This makes is difficult to track where in a sequence a user of a site is – have they just logged in or are they proceeding to the checkout? ASP allows a number of techniques to be used to track a user through a site, from the deployment of special ‘Session’ objects which are embedded in each page returned to a client so that they can be retrieved on the next request, to the use of ‘Cookies’ – strings that can be stored in the client’s computer from page to page (or even session to session). We can also use a couple of web programmers’ tricks, such as storing session data in variables hidden in web forms to be passed back and forth between server and client. All of these techniques involve embedding session data in the response to a page request, with the page organised so that the same data will be returned if a link on that page is used.
The Response World- Wide- Web Next Request
Web Server Figure 6: Session state is maintained by sending data back and forth between the server and the browser embedded in the request-response data. The envelope here depicts this session data. All of the methods used to store data between ASP pages are there to save having to store the data at the server, where they could take up valuable space that would limit the number of simultaneous clients that could be serviced. The result is that well- designed web sites are inherently ‘scalable’, meaning that the software imposes no limit on the number of clients that the site can deal with at any one time. Of course there are limits imposed by the hardware the site is running on, the speed of the internet connection that the server has and other factors, but not the ASP website design.
Application state
ASP applications place demands on a web server, and it would be unwise to create a site that subsequently hogged space on the server whether it was servicing any clients or not. Managing session state goes a long way to reducing the load on a server, but a server could easily fill up with inactive ASP sites because each site must maintain a certain amount of information simply to function. A website typically keeps track of such things as the number of current users, page statistics (how many times each page has been visited) and database connections that can be used by a number of simultaneous sessions. Note that while session status multiplies up by the number of current users, application status is effectively one lot of stored data per application (or active website). i.e. the problem of maintaining application data is not anywhere near as bad. Even so, an application consumes some resources, and so it would be useful if we could cut-back on it (or even remove it completely) if there were no requests coming in for pages within it. Global.asa, one of the code files that are automatically associated with a web application, can contain code to perform application housekeeping. A realistic example of a suitable Global.asa file for a website is given later in listing 13.
Development Choices
When we decide to create a dynamic website, we have a number of choices to make – which web-server software, how the site will be hosted, what language to use, how we will write and test the code, how we will arrange the files stored on the server etc. The choice of web-server is one that should be a simple matter of preference – a number of web servers are available for free to install on most PC operating systems. If you are lucky (or wealthy) enough to have a permanent broadband connection to the Internet, or are creating a web-site for a business that has a permanent internet connection and a computer designated as a web-server, you can use whatever combination of operating system and web-server takes your fancy. This is easy for your Internet Service Provider to manage, because since you host all of the website and server facilities on your own computer, they need only provide a path to your PC from the Internet. Also, the risk of a badly designed site causing a server to crash, or worse, be open to malicious access from the community of Internet crazies, is yours to take and will not seriously affect the ISP or their other clients. If you have a dial-up internet connection, you will be restricted in how you create your active website (with some Internet Service Providers [ISPs] you may not be allowed to host an active website at all). ISPs often provide a restricted range of facilities for hosting dynamic websites, limiting your choice of database (if any), scripting language and configuration options. The reason for this is simply that with a dial-up connection, your entire website resides on the ISP’s own servers, and when a script is executed it runs on the ISP’s server, so you can only use those facilities the ISP has decided to install on their server machines. ISPs also have to restrict what your scripts can do on the server to ensure that they do not leave themselves open to malicious attack, and some find that the safest approach is simply to not host such business. Fortunately, you are free to choose among many ISPs, and so there ought to be a good range that provide the facilities you need to operate your site. In the practical sessions, we will be going down a decidedly Microsoft route. The server you will write script for is IIS (or PWS, which provides very similar facilities), the database you will write code to interact with will be Access, although you will find that the code you create will also work well with a SQL Server database, give or take a minor configuration change or two.
Tools
Once you have mastered the basics of writing ASP code, you will also be able to choose which tools you make use of to build the website. However, in these early practical sessions, we will use a very minimal toolset – a copy of Microsoft Access (for creating the database and checking the results of our ASP endeavours), and a simple text editor (Windows Notepad will do at a pinch). Microsoft FrontPage is a good application program for developing ASP websites (or static ones for that matter), providing good facilities for testing page behaviour, highlighting code syntax (by colouring the HTML/ASP text), different ways of viewing a page of a website or the structure of the whole site, and some tools that make it easy to insert some of the more complex HTML mark-up elements into a web page. FrontPage also allows databases tables to be inserted into a web page quickly, without the need for ASP script. However, the built-in database facility only allows simple data from a specific table or query to be inserted, and does not allow the creation of more complex data management pages. In these tutorials, we’ll use ASP to provide as much flexibility as we can.
IIS – Installation Issues
If you have a computer that runs either Windows 2000 or XP professional, you are likely to have Internet Information Server installed already. If it is not installed, you will need to run the Windows Setup program from the CD-ROM that your operating system was supplied on, and select the option to install IIS – currently this option appears on the Internet section of the Tools page of the setup program. Different versions of the Windows operating system do not include a copy of IIS. Windows XP home does not include a web server at all, although Windows 98 and Millennium (ME) come with a copy of Personal Web Server (PWS), which is effectively a cut-down version of IIS that has all of the capabilities that we need for developing websites. Consult the manuals or help files of the CD to find out how to locate and install the web server with these operating systems. Once you have a web server installed, you will need to create web sites on your computer to place your ASP code in. In IIS and PWS, creating a website is a simple matter. To create a new site in IIS on a Windows XP machine: 1. Select StartAdministrative ToolsInternet Information Services 2. In the tree view on the left of the IIS display, right-click on Default Web Site, and select New…Virtual Directory from the context menu that pops up 3. Follow the directions of the New Virtual Direction Wizard to set up a site within your web server. The steps are: a. Provide a name for the virtual directory – this will become the root name of the site your are creating (e.g. Dreamhome) b. Type or (more likely) browse to a folder that will house the files on the virtual directory. In a standard IIS installation, it is expected that you will place the files in a folder off C:\Inetpub\wwwroot. You can place the files in a different folder or on a different drive if you wish. c. Select the required settings for file access for your web page files from the Internet. The default is Read and Run Scripts, and this is a very sensible default. You are best to have a very good reason for choosing other settings for this, since you may be allowing hackers to gain access to your hard disk if your website is every published across a broadband connection d. Press the Finish button at the last stage of the wizard. You now have a root folder for a named website. 4. At this stage it is useful to test the website. Drop a very simple HTML file or ASP file into the root folder you created (e.g. in C:\Inetpub\wwwroot\MySite) – listing 1 or 2 (later) are ideal for this. You should now be able to access these files via the web server as follows: a. Run Internet Explorer b. Enter http://MyMachine/MySite/Hello.asp into the address bar and press enter. Of course, you should replace MyuMachine with your actual PC’s name, and MySite with the name you gave the virtual directory. Alternatively, you can use http://localhost/MySite/Hello.asp since the name localhost is reserved to refer to the web server that resides on the local computer (the one that you are running the browser on). Note that the localhost name will only work from the local computer, and browsing from any other machine will require the actual server name. The result (with Hello.asp from listing 2) should be a page that displays a message and the current time. This last part is important – if the time is not displayed, you have typed up the ASP file with an error in it, or your server is not executing the script properly. Fix this now, before you go on to try to create any other active web pages.
ADO
Before we move on to examine the ways we can move data between web pages and a database, a quick recap of ActiveX Data Objects, or ADO, will be useful. ADO is a database access layer developed by Microsoft using ActiveX. ActiveX is no more than a marketing term used by Microsoft to describe their component-based object technology COM, or Component Object Model. The term ActiveX has generally been unpopular with developers, and even Microsoft employees have been known to explain that the ‘X’ is silent in Active(X) Data Objects. ADO is a simple API (Application Programmers Interface) for accessing databases. It is essentially a software component library hosting the small number of components that are necessary to retrieve data from and update data in databases. There are three essential types of object you will need to learn to use to access data: Connection objects: a connection is a software ‘object’ that provides an interconnection between a piece of software and a database. It has been designed so that it is easy to access data from almost any type of database, including Microsoft Access, Paradox, dBase, Oracle, SQL Server, and even structured text files and the data stores used by email servers. Typically a connection object is deployed in a script to create a connection to a particular database and send commands to it Command objects: some of the commands that are sent to a database are more complex than a simple connection object (which has a job of its own to do maintaining a database connection) can handle easily. Typically, when a command contains a number of associated pieces of information (parameters), a command object is used to package and dispatch it via a connection. There is no real need to use command objects for most database operations, but it can make some of them easier to handle Recordset objects: one thing we often want to do is to retrieve data from a database. Using ADO, this data is almost always returned in the form of a Recordset, which acts like a table of data held in computer memory. A Recordset can contain a whole table of data, but more typically, Recordsets are used to collect the results of a query – a single record from a table or joined tables, several selected columns from a defined set of rows in a table, in fact any data that can be the result of a SQL select statement. Recordsets give us access to the information that is in a database, and also allow us to add or change data in databases from an ASP script In addition, there are other types of ADO object that we do not normally deal with specifically – a Field (a single column of a single record of data) will give us access to actual data attributes, and an Error will provide us with information that indicates what went wrong when an ADO command can not be executed for some reason. Fields come to us as component parts of Recordsets and so we tend to work with them without explicitly referring to them (this will become clearer after a practical example). A collection of Errors is maintained by the Connection object, and can be examined by script code whenever some ADO operation is executed to determine whether it worked or not.
Object Model
ADO objects are packaged for deployment in a Dynamic Link Library (DLL). This is nothing to worry about – it simply means that we can access ADO objects from a running script. Each ‘object’ we wish to use must first be loaded into computer memory (a service provided for us by IIS) and then set up for use. The steps in doing this may at first seem complex, but they are a simple recipe we repeat any time we want to make use of an ADO object, and are hugely less complex than the underlying functions that the objects are performing for us. The ADO object model is organised as shown below: Connection Recordset
Errors Fields
Properties Properties
Command Properties
Parameters
Properties
Figure 7: The ADO Object model A Connection object potentially contains a collection of Error objects and a collection of Properties. Error objects only exist if, after executing some operation, something has gone wrong, and they are there to provide information as to the cause of the problem. Properties are ‘settings’ that apply to a connection – for example, the type of database it connects us to, the name of the database and an indication of whether it supports transactions (coherent sequences of commands). Similarly, a Recordset object contains a number of Fields (each field represents the name, type and value of an attribute in a database tuple), each of which can have Properties, and a set of Properties of its own (for example, the number of records in it, an indication of whether we are at the end of the set of records). A Command object has a set of Parameters (each indicating a piece of information that can be sent to or retrieved from a query) and some Properties (the type of command, its name and whether it will return a Recordset or not) This small set of objects is enough to enable us to do whatever we wish to an existing database. The objects contained in ADO are interrelated so that they collaborate on performing data access tasks for us. A typical sequence of operations we might perform to retrieve some data for display from a database might be something like: 1. Connect to a database 2. Open the database (making the data in it accessible) 3. Send a SQL query to the database connection defining the set of information we want 4. Using the Recordset that is returned from the connection as the result of the query, step through the current record in it, displaying the contents of each field in the record 5. Try to move to the next row in the Recordset 6. If the next row is not empty, return to step 4 7. Close the Recordset 8. Close the database connection This sequence of steps indicates something about the structure that relates the objects in ADO. A connection is capable of creating a Recordset, and a Recordset contains a sequence of records (rows), each of which may have a number of individual Fields (attributes). The relationships between these objects is structural, and is sometimes referred to as an Object Model – the way in which objects are interconnected to form a coherent and useful assembly. The way we step through the operations is typical of the flow of instructions in an ASP script - a step by step sequence of small tasks that incrementally perform a larger overall task. As we step through such a sequence, the various ‘objects’ in ASP are made to interact so that they collaborate on some overall task (for example, in steps 3 and 4, we send a SQL query to a connection, which responds by giving us back a Recordset full of data). In this way, the object model, rather than any individual object, is responsible for performing some task.
Database Neutrality
One important feature of ADO is that it tries not to make distinctions between different types of database. The ADO code to retrieve data from an Oracle server is exactly the same as the code we would use to retrieve the data from an Access database with a similar data structure. It is impossible for ADO to be 100% neutral in this respect (some database systems provide advanced features that not all of them do), but as much as possible, ADO hides the idiosyncrasies of the underlying databases, which is a very good reason to use it. By providing for transparent interaction with any of a range of database types, ADO makes it possible to change the underlying database without ADO code needing to be radically re-written. For example, I may start with a small website that caters for a small number of visitors and use an Access database as the underlying database. If my website became very popular over time, it might be sensible to transfer the data to a SQL Server database, since this provides for much higher data throughput. Using ADO, only minimal changes would be needed to make the transition from Access to ADO (provided I did not immediately need to make use of some of the more industrial-strength features of SQL server, since for these, it would almost certainly be necessary to change the ADO code significantly).
IIS Server Objects
IIS (and Personal Web Server) make a number of standard objects available to ASP code. Typically these objects perform complex functions such as extracting useful information from web requests, packaging up web responses to send back to the clients’ browsers, and maintaining the state of clients’ sessions and the application itself. It also provides a simple mechanism for deploying other objects that are not part of IIS, such as ADO connections and commands, on request. IIS separates out ASP code from html code as it sends a response back to a request. While plain HTML is passed directly into the response, ASP code is executed by one of the available script engines attached to IIS. The script engine interprets the ASP code (e.g. VBScript), and returns a result to IIS, which then passes this on into the response. ASP script is lines of script code within any script tags <% and %> in an ASP file. A typical script statement might evaluate an expression (e.g. 2+2) and calculate its result (e.g. 4). An ASP file may contain any number of blocks of script interspersed between blocks of HTML, and in each case, IIS will direct HTML straight back into the response but will have ASP code executed by the script engine. Within the ASP statements, there will usually be references to a number of objects that IIS is aware of. These objects perform standard functions that would be too complex or too mundane to write script code for. Objects in IIS are responsible for representing information about the page request (the Request object), sending and controlling the sending of results back into the response (the Response object), managing various aspects of the server engine itself (the Server object) and keeping track of information that is used by the entire ASP application (the Application object) and by individual sessions (the Session object). Other objects collect data from a client’s browser (Form), store data on a client’s PC (Cookies) and allow script to access information specific to the server (ServerVariables).
Server
The Server object is used mostly to create other, non-native (to ASP) ob jects. For example, to create an ADO Connection object, we would use a statement like: Set conn = Server.CreateObject(“ADODB.Connection”) where “ADODB.Connection” is the name used to identify database connection objects to the Windows registry. We can also get the server to do other things that are not specific to any one website on the server, such as: Server.ScriptTimeOut = 90 to set the maximum amount of time (90 seconds) the server will allow any one ASP application to spend on responding to a single ASP request, or DatabaseName = Server.MapPath(“Dreamhome.mdb”) to work out the actual location of a file (in this case a database file) on the computer running the server.
Global.asa
Global.asa is the name we should give to a file of ASP code in the root folder of a website that defines routines that will be run automatically when certain things occur – the first page request for the site is received, the site has been inactive for a preset period of time, a new user sends a request in for a page, or a user completes a session.
Application
This object allows us to define variables that will be available throughout an ASP website. For example, if we wanted to create an ADO database connection object that could be accessed from anywhere on the site, we could use this code: Set conn = Server.CreateObject(“ADODB.Connection”) conn.open DBCONNECTSTRING Set Application(“Conn”) = conn
Now, wherever we were on the website, we could access the database, for example to execute a SQL Select statement, in code like this… Set RS = Application(“Conn”).Execute(“SELECT * FROM Client”) ‘ Can now go on to use the Recordset RS… The sequence Application(“Conn”) is used here to set or retrieve a variable that is accessible to the whole application – Conn is the name given to the variable – in this case a Connection object. The Application object is also used within Global.asa to define things to do when an application starts (when its very first request is received). For example, we might place the code listed above to open a database connection in Global.asa so that a connection is automatically opened as soon as the first visitor arrives (like opening the first bottle of wine as soon as the first guest arrives at a party – the wine will be open for subsequent guests to arrive):
‘ Code in Global.asa
Sub Application_OnStart() Set conn = Server.CreateObject(“ADODB.Connection”) conn.open DBCONNECTSTRING Set Application(“Conn”) = conn End Sub Listing 3: The Sub in Global.asa that initializes an active website. The code Sub Application_OnStart() defines the entry point to a subroutine (a block of code that is executed as a sequence of instructions) that will execute automatically when a site starts up.
Session
A session object can be maintained for each and every current user of the site. This allows us to store a small amount of information for each user between pages – for example, we can establish who a user is when they first log in to the site by making them visit a log-in page, which would allow us to authenticate users of a restricted site, or provide us with an identity that we can use to record purchases in a shopping cart style website. Once someone has logged in for the first time and we have collected some data on their identity (typically in a database Recordset), we would not want to ask them to log in again for each page they visit, so we could store the user’s login-identity in a session variable: Session(“UserID”) = RS(“UserID”)
In the above statement, RS is the database Recordset containing user data, and UserID is the name of the field in the current record that stores the user’s identification (typically a customer number, or possibly a nickname or email address). Now, in each subsequent page-visit, the user’s ID will be accessible as: Session(“UserID”)
Since we can create and use as many session variables as we like, we could continue to define more variables to store, for example, user’s name and other details, details of current purchases in a shopping cart, and so on. However, since each session variable will require a block of information to be passed back and forth between the web server and the browser each time an ASP page is accessed, the result of too many session variables can be to slow down the web accesses and make the site appear more sluggish. For good website design, it is better to minimize the amount of data being passed back and forth between browser and server – typically we would store the bulk of the data in a database and just use session variables to pass key values back and forth, so that we could always identify the database entries that stored the information we needed.
Request
The Request object is used in ASP script to gain access to information that comes from the browser. It has four properties that give this access: QueryString: simple interactions with an ASP page (GET operations) can contain further information in the (modified) URL in the form of Name=Value pairs. The QueryString property allows these to be accessed. Form: this property allows you to retrieve values entered into and POSTed from a form on the requesting web page. Each control on a HTML form is represented in the form object, and the collection of Form values can amount to a significant quantity of information sent from a browser to a website ServerVariables: Using this property, you can determine the type of browser that sent the request (e.g. Internet Explorer 5.0, Netscape) and other information (e.g. the visitor’s IP address) Cookies: this property allows you to access data that you previously stored in the user’s computer; these are typically small configuration files that allow you to recognise a browser that had previously visited the site, and are typically used to allow you to ‘personalize’ the pages you send back. QueryString There are two types of request that can be sent from a user’s browser. A GET operation (the simplest one) can contain up to 255 characters worth of data appended to the URL used to access your site. For example, a HTML file might contain a number of different hyperlinks which all lead to the same ASP page. To identify which link was used, the hyperlinks could include a different Name/Value pair in each link. For example,
Figure 8: A hyperlink with a query string (link is displayed in the status bar). Note the four links at the bottom of the page (First, Previous, Next and Last), and the URL shown in the status bar, which is the URL that will be used if the mouse is clicked when the pointer is over the ‘previous’ link, as shown. This would be coded into the html page as a set of page-links as shown in bold below:
DreamHome Estate Agents
Information: Select a page...
First Previous Next Last Listing 4: HTML code with hrefs defining links with query strings. The file getInfo.asp will be able to determine which link was clicked on by retrieving the value QueryString(“info”) (which will be ‘prevpage’ if the ‘Previous’ link was pressed). Form GET operations are ideal for sending a small amount of information to the server. Several values can be passed to the server, provided the length of the entire set of name and value pairs passed does not exceed 255 characters (this limit must include the delimiters ‘?’ at the start of the list of QueryStrings, ‘=’ between each name and value pair, and ‘&’ between successive name/value pairs). If it is necessary to send more data from the browser to the website, a POST operation can be used. The POST method can deal with much larger amounts of information. It is also a more convenient way of sending data from a Web Form – an area embedded in a web page that contains controls that the user can enter data in to. In a POST operation, data is again sent in Name/Value pairs, but now these are sent as a separate stream of binary information, retrievable from the Form property of the Request object. For example, a web form can be used to pass registration details to the website:Figure 9: A HTML form – each control on this will provide data that can be collected from the Request.Form object All of the values entered into this page on the browser by the user will be sent as name/value pairs by the POST method. The html for the form is:
Join our Mailing List
Please enter the details below (do not omit any items marked *):
Listing 5: HTML code to produce the form shown in figure 9 All of the controls on the above form are encoded in the web form as , or
The data would have been left on the site by assigning a value to a cookie in the Response object’s Cookies collection. Storing small amounts of data like this can do no harm to a client’s computer and can be used to enhance the way they use your site. For example, you can personalize a page so that it is able to greet the client by name, remind them of their current status or guide them to new information that might have been added since the last time they visited the site. However, the Internet is no longer a medium that you can trust (whether you are a client browsing web-sites or a host of a web site); some clients may be malicious and try to extract sensitive information from your site, some websites act in highly suspect ways leaving small bits of software that can track your web page usage or even relay all your keystrokes back to the site (a serious security problem if you do Internet Banking, for example). Since cookies can store data that other websites might misuse, some people turn off the facility for their browser to store them, and since we can not every guarantee that a client will allow cookies, it is best not to assume that any client does. Response
The response object is there to allow you to direct information back to the browser that issued a request. It provides ways to control how the information is sent to the browser (whether it is sent in small chunks as and when the ASP page issues its Response.Write statements, or collated into larger blocks of data to save information ‘dribbling’ back to the browser if a request may take some time to process) and allows data to be sent to the browser directly (Response.Write) or from another file (Reponse.Redirect). Mainly, the Response object is used to ‘write’ data back to the browser, whether this is literal text (Response.Write “Hello Client”), the result of Script functions (Response.Write Date), data retrieved from an ADO data session (Response.Write RS(“ClientName”), or a mixture of all of these: Response.Write “Hello “ & _ RS(“ClientName”) & “ we’ve not heard from you since “ & _ Response.Cookies(“LastDate” (Note that in VBScript, a statement, which normally must appear in a single line of code, can be broken to run over several lines, by inserting line continuation sequences [a space followed by an underscore] between elements.) Everything we want to do in an ASP site will require some support from some or all of these server objects.
Web Page Development Issues and Strategies
Now that we’ve been introduced to the components that are used to make up an active website, we ought to look at some of the problems inherent in creating a website that derives most of the information it publishes from a database.
Database Connections
The ADO connection object described earlier is our conduit to the source of information for our web sites – one or more databases. If we were building a desktop application, we could figure out in advance how many distinct connections we would need to support the functions we will need to provide. Some developers open and close connections at will, creating a new connection and opening it at the drop of a hat. Others try to minimize the number of simultaneous connections open since each consumes computer resources and will present a certain ‘load’ on the database server (or on the database ‘driver’ if the database is on the local computer, as an Access DB would be). The former strategy can work well if it is not taken to extremes, the latter will always work but may involve a lot of creating and destroying of connections which can add significantly to the work the processor (and database server) must do. Connections into a database that will be accessed by an unknown number of users via their web browsers is a different story. Since we can’t ever predict how many users there will be, we need to be a bit more frugal with database connections. Each connection takes up memory and processor time, so allowing new connections to be created willy-nilly is a sure-fire recipe for a system that will eventually grind to a halt. There are three ways around this: 1. Every ASP page that uses a database connection can be required to create the connection object, open the connection, use it, close the connection and finally destroy the connection object (remove it from the server’s memory). This approach requires discipline on the part of the developer. 2. A connection can be created and opened on receipt of the first request for an ASP page. This connection can be shared as a part of the Application object’s state by all users. The reduced workload on the server will be significant, since creating and destroying objects over and over again can impose a significant burden. However, this approach will cause problems if the website grows to such an extent that additional web servers have to be deployed. In this case, all the web servers would now share the one connection and the resulting contention where two pages try to simultaneously access a server would cause some delays 3. A ‘pool’ of connections can be managed by a group of servers up to some specified limit. Initially, there will be no servers in the pool, but as requests come in, connections will be opened and left open. Whenever a request arrives and there are no open connections lying idle, another connection is opened, up to the maximum number. Facilities for this type of connection management are built into Microsoft’s Enterprise Server software For our purposes (reducing the server’s workload), we’ll choose the second method as the most appropriate. If the website were to grow significantly we might need to revise the strategy, but that is a problem we don’t need to consider until our website has made us rich enough not to worry about re-developing the site. The ideal approach to deal with a single connection left open for all users is to create it in Application_OnStart() (the event handler we add to Global.asa) and make it available as an Application() state variable. To make this work, we’d add a text file called Global.asa to the root folder of the website, and then place the following code into it:
‘ This will make sure the database connection is open and ready… Sub Application_OnStart() Set conn = Server.CreateObject(“ADODB.Connection”) conn.open GetConnectionString(“Dreamhome.mdb”) ‘ *See later Set Application(“Conn”) = conn End Sub
‘ This will close the connection if we shut down the site… Sub Application_OnEnd() Application(“Conn”).Close() End Sub Listing 6: Code in Global.asa to automatically open and close a database connection. In any ASP page that requires database access, the following code will allow it: Dim RS Set RS = Application(“Conn”).Execute( …
Client ‘state’
If our site makes use of sequences of ASP pages to perform compound tasks (as most active websites do), we will need to make sure we keep track of each client from page to page, and possibly track other things, such as the state of a shopping cart (e.g. all the items currently in it), the state of a currently active transaction (e.g. to indicate that data submitted on a form has been stored successfully).or some other business processes. The most convenient way of doing this is to use ‘session’ variables. For example: Session(“ClientID”) = Request.Cookiies(“ClientID”)
The above statements sets up a session variable, Session(“ClientID”) so that it can be retrieved at any subsequent point on the current session. If the client returns to the current or some other page the site within the session timeout (a number of minutes that you can set in ASP code), and if the current session has not been terminated (using the statement Session.Abandon), we can retrieve the value of ClientID with this statement: ID = Session(“ClientID”) Rather than store all ‘live’ information in session variables, it is often best to store this information in a database as and when it arrives. Part of the web database then becomes a repository for data that is in some half-way state, and so we would need to add to the tables that stored this type of data a column that indicated whether a given record was ‘pending’ or ‘completed’. For example, in a shopping cart application, we could have an OrderDetail table which stored individual items from an overall purchase. We might organise the table as:
Figure 10: A data table that could be used in an e-commerce site to store the state of a client’s shopping cart Note the last column of this table, LineTotal. You may consider that this attribute breaks the normalization of the database since it contains some information that is derivable from other attributes in this and other tables (the LineTotal value is the Quantity attribute of this table multiplied by the UnitCost attribute of the Product table, referred to by the ProductID attribute) – you are right, but this is a situation in which that redundant information serves two very good purposes. Firstly, if in the future the UnitCost of a given product was to change, we would not want to retrospectively alter all of the order information about purchases that were made before the price change – this attribute protects against that by storing the actual cost at the time of purchase. Secondly, and most importantly for our purpose of tracking a series of purchases over time, the LineTotal value can be inserted as and when an order is completed. We now have a way of tracking which orders are yet to be completed – i.e. those which are currently in the shopping cart but have not yet been checked out, by examining whether the LineTotal field is Null or not. From this we can see that OrderDetails 3 and 4 have not yet been checked out. When customers 3 and 2 next visit the site, these orders will be waiting for them to make up their mind on, and we can arrange the site to give them the chance to either cancel or complete the orders. If you have ever gone to a web site to make a purchase and, reaching the checkout stage, discovered items that you had selected on a previous visit and then forgotten about sitting in your shopping cart, you will have been a participant in this method or some variation on it. From the website manager’s point of view, this is a very positive thing – customers can visit the site over a period of time adding purchases to a shopping cart, and every time they come back, the cart is still waiting for them, and the purchases are more likely to go ahead.
Cookies and client tracking
Ideally, a client who returns to an eCommerce web site ought to be recognised. In the same way that when a customer is happy to be recognised and greeted by name when they return to a shop, so a website that deals with customers can, by some very simple means, keep track of them to make them feel like valued customers. The only reliable ways we have to track visitors to a website are that we either ask them to log in on the first page in a session, or (ideally) we ‘remember’ them by using a cookie. Unfortunately, some people will disallow the use of cookies, and so if we do intend to use them, we should always have a fall-back position. When a session starts, we should check for a cookie that identifies the client (a number in a database can be used as a primary key, and we can also make this the ID we store in the cookie). If one exists, we can look up the client’s details in the database and send back a personal greeting at the top of a page. If not, we can ask the client to log in as an existing customer, or click on a link to a log-in screen if they are not an existing customer. Given a database table of client details, we can arrange for this as follows:
‘This code should be in Index.asp so that visitors start here. If Request.Cookies(“CustID”) = “” Then ‘This is either a new client or one who does not allow cookies… Response.Redirect “login.html” Else ‘We know this client… Session(“CustID”) = Request.Cookies(“CustID”) Dim SQL SQL = “select Name from Customers where CustID = ‘“ & _ Request.Cookies(“CustID”) & “’” ‘ Now go on to greet the customer and show the initial page… ‘ …. End If Listing 8: Retrieving a client’s ID from a Cookie, and using this to get their name from a database The page login.html would provide a form for the customer to enter their email address and password and a link to lead new customers to a registration page. Note that while I am using a numeric CustID field here (this is easily generated by Access using an autonumber field), it is sometimes useful to make a client’s email address as their log-in identity – it is guaranteed to be unique and they are unlikely to forget it. Whatever is used for the customers’ ID field, they should also be required to provide a password on log-in, since otherwise it would be possible for strangers to get access to client’s details by fishing with random numbers or email addresses.
Queries, Actions and Recordsets
There are two types of operation we can ask an open ADO connection to perform. One is to ask for data to be returned in the form of a Recordset, and the second is to ask for some update-type operation to be executed. In the case of the second of these, we do not expect a Recordset to be returned as a result, but could expect some indication of whether the operation – either an Add, Delete or Update – was successful or not. The distinction made is that a query that results in a Recordset is a select query, while the other type is an action query. When we issue a select query, we need to assign the resulting Recordset to a variable:
Dim RS ‘ This will act as a reference to the returned object Dim conn Set conn = Application(“Conn”) Set RS = conn.Execute(“select * from OrderDetail where CustID = “ & _ custID) ‘ We can now go on to use the returned Recordset… ‘ …. Listing 9: Getting an ADO recordset In most normal situations, the Recordset returned from a select query will have either a single record (e.g. if the query issued was to retrieve the details of a particular customer with a specific ID number) or an unknown number of records (e.g. all of the current list of items in a customer’s shopping cart). In the former case, you will generally want to pick up the data and do something with it. First you should check whether any actual data was returned: Set RS = conn.Execute(“select * from Customers where CustID = “ & _ custID) If Not RS.EOF Then ‘ A customer record has been retrieved – do something with it… Response.Write “Hello “ & RS(“Name”) ‘ more actions… Else ‘ No customer record, so we need to log the client in… Response.Redirect “login.html” End If Listing 10: Checking whether a specific client exists in the database RS.EOF (End Of File) returns true if we are at the end of a Recordset (i.e. there are no more records in it). In the case where the Recordset has just been obtained, the first record should be current, so if EOF is true, there can be no matching record (the required match is for the given CustID value). For a query where any number of records can be expected (e.g. a customer can have zero, one or any number of matching orders in the OrderDetail table), we would typically step through them one at a time performing some action: Set RS = conn.Execute(“select * from OrderDetail where CustID = “ & _ custID & “ and LineTotal Is Null”) Do Until RS.EOF ‘ A customer record has been retrieved – do something with it… Response.Write “Order Item “ & RS(“ProductID”) & “ Quantity “ & _ RS(“Quantity”) RS.MoveNext Loop Listing 11: Stepping through each record in a recordset Note that here we have asked for all of the OrderDetail records for a specific customer (CustID) where LineTotal is a null value. This was our indication that the order item had not been processed yet, and so we’re displaying the id and price of items left in the shopping cart. The Do..Loop surrounding the statements is effectively – keep doing this until there are no more uncompleted orders to display, and note that the whole thing hinges on the RS.MoveNext statement at the end of the loop – without this, the same order’s retails will be written out to the client’s browser forever (or until either the web response times out or the client gets bored and moves away from the site). An action query does not return a Recordset. However, we can get some indication of whether the action was successful or not by checking for any errors after the command is executed: Dim conn Set conn = Application(“Conn”) Conn.Execute(“delete from OrderDetail where CustID = “ & custID) If conn.Errors.Count = 0 Then ‘ Success… Else ‘Something did not work… End If Listing 12: Finding out if an action query worked
The Dreamhome Active Website
You should be familiar with the Dreamhome example database from the Connolly and Begg book. While that database and the examples of tables, queries, forms etc. shown in the book were organised to make the links between data tables clear, a database that was to be managed by ASP code would never be constructed in quite that way. For a start, the primary key fields used (CRXX for client record, SXXX for staff, PXXX for rental property etc.) were devised to be easy for a reader to recognise and not for the practical necessities of running a commercial website (e.g. no real company would allow only 2 digits for the client number since a genuine realtor would be looking for that many clients per week). The sample application you can build as an Active website uses a variation on the Dreamhome database. Only a few tables are defined, and these are organized to be ‘automation friendly’. The structure of this Access database is shown below:
Figure 11: The Dreamhome rental database – this is a subset that will be managed by ASP code In this variation of the database, the PropertyForRent table contains attributes that specify a property (address, size and links to pictures of the house and its floor-plan), as well as links to the Branch that deals with the property, and the member of Staff who is responsible for it. The Viewing table lists details of appointments made by clients (through the web site) to view a rental property, and the Client table lists the details of the clients who have made the viewing appointments. There are a number of practical issues that make this database structure as unrealistic as the original for the purposes of running a property agency, but the structure is perfectly adequate for illustrating how a database can be managed by a web site, and easy to understand.
The database tables
For practical purposes, we would normally group database tables into two distinct groups – those that would be managed locally by the staff who run the company, and those that need to be managed by web pages. For the tables to be managed by web pages, we need to ensure that creating and managing records is as simple as possible. Specifically, this means we must ensure that data can be added to the Viewing and Clients table without intervention from staff; the primary key fields should be a simple numeric value since Access can generate these freely, while the coding style used in the other tables may be more meaningful, but would be more awkward to generate programmatically. The only other significant change is to the Staff table. Since this is information that will be viewed on a website, it makes sense to add contact information to the staff table (Telephone, Mobile and Email).
The site structure
An active website can be complex, even though individual pages may be easy to develop. Each page of a website is a potential target location that a client can bookmark in their browser, and so it is possible that clients will arrive at a page without having gone through any necessary pre-requisite pages. For example, if a client arrives directly at the page to book a viewing of a property without having first identified either which property they wish to view, or who they are, we must direct them off to pages that will let them do these things first. It is always a good idea to start with a list of the specific operations you wish to allow to be performed from a web browser and then considering all of the prerequisites for these. For example, we’ll go on to create web pages to do the following with the Dreamhome database: 1. Contact a member of staff at a branch if necessary 2. Join a mailing list of clients, so that you can be informed of any new properties that might meet your interest 3. View a list of properties that meet your criteria – right area, right size and right rental cost 4. Arrange to view a property at a time that is mutually suitable to you and the staff of the branch that has the property on its list 5. Send comments about a property you have viewed – is it suitable, do you want to rent it. This is a fairly small list of requirements compared to most commercial websites, but it does cover all of the necessary ground – you can view the ‘stock list’, reserve an item from the list (for viewing), arrange to take a particular stock item (a specific property viewing at a specific time) and complete the deal (reject or rent a property). However, in common with other e-commerce websites, there are a number of requirements that are not stated, implicit in the need to make the above requirements work. For example, joining a mailing list (requirement 2) requires that you must be able to upload some information about yourself – contact details as a minimum, but it would be as well also to include preferences about the types of properties you would be interested in. A mailing list enables the realtor to send information to you (by email or mail) whether you visit the website again or not, so it makes business sense for this facility to exist. When you find an interesting property listed on the site, either by browsing (requirement 3) or because a mailing list directed you to it, you will wish to book a viewing for it (requirement 4). That means you will need to create a viewing record, and this in turn will mean the site must be able to identify you by locating the appropriate mailing list entry. This will mean you will either have to log-in to the site before booking a viewing, or the site will have had to identify you automatically. When you wish to add comments about a property you have subsequently viewed (requirement 5), you will need to return to the viewing record created earlier, and again either the site will need to identify you in some way. Overall, in addition to the main requirements listed above, we need to provide for the following: 6. A visitor who accesses the site to book a viewing must either have their mailing list record retrieved, or, if they are not yet on the mailing list, must join it, so that we are able to create a booking for a known client 7. A visitor to the site must be able to view past booking records which are not yet resolved, so while the visitor must already be a client to make this possible, we must be able to recognise them as such. Creating the Dreamhome Active Website
The remainder of this document will go through the various stages needed to create the website, assuming a database as shown in figure 11. The entire site is available on the book website (where you got this document) as a zip file. You can either create all of the html and active server page files by entering the code in the listings below, or extract the files from the zip file into a folder that IIS has Virtual Directory access to. In either case, you will need to set up an appropriate virtual directory, and an associated folder in your wwwroot folder. Note that the following instructions assume that you have a working installation of Internet Information Server: 1. Create a folder directly under wwwroot to house the Dreamhome website – call this folder Dreamhome (i.e. c:\Inetpub\wwwroot\Dreamhome)
2. Run the Internet Information Services applet (from the Start button, select Administrative Tools, and then click on Internet Information Services). Click on Default Web Site and make sure that it is currently operational (in the Action menu, the Start item should be greyed out)
3. Right-click on the Default Web Site entry on the tree-view at the left, and select New, then Virtual Directory
4. In the Virtual Directory Creation Wizard that appears, click on Next, and in the VIrtual Directory alias page, enter the name Dreamhome in the text box marked Alias. Click Next again
5. In the Web Site Content Directory page, press the Browse button, and browse to the folder you create under wwwroot (Dreamhome). Select this and press OK
6. In the Access Permissions page, accept the default selections (Read and Run Scripts). Click next
7. If no error has been reported, click Finish to complete the creation of the new Virtual Directory to host your website.
All of the files that are needed to run the website will be placed in the Dreamhome folder, or folders placed under it. Do not delete the folder (_vti_cnf) that was automatically created by IIS – this is needed for the management of the site. Adding folders and files
Apart from the htm and asp files you will need to run the website, you will also need to install the database file (Dreamhome.mdb) and image files (*.jpg) available within the zip file from the book website. Once you have downloaded it, open the zip file (either double click on it from Windows XP Explorer, or use a zip manager, e,g, Winzip, PowerArchive or some other to open it) and extract Dreamhome.mdb and the all of the .JPG files from it. Dreamhome.mdb should be placed inside the Dreamhome folder, and all of the image files copied into a folder created for them. Create a new folder under the Dreamhome folder, call it Images, and place the graphic files there.
Code files
We will need to create HTML and ASP pages to fulfil the list of requirements shown above, and the normal requirements of operating a website. As a starting point, we need to create global.asa to set up Application and Session variables necessary to operate the site. All of the remaining files should be created directly in the Dreamhome folder:
Global.asa
Listing 13: Global.asa – Code to set up and clear up Application and Session variables for the site Global.asa contains a number of functions. The first of these,
GetConnectionString(), is a simple housekeeping function that returns the connection string needed by an ADO Connection object to create a link to the database. It works on the assumption that the database is an Access database file (.MDB) and that it is in the same folder as the ASP code that uses the connection. We can move the database to a different folder provided the parameter ‘db’ passed to the function includes the relative location of the database – e.g. “databases/Dreamhome.mdb”, if the database was in a folder called database within the site home folder.
Application_OnStart() is a Sub (subroutine) that ensures that a database connection is formed and open as soon as the first request for a page within the site arrives. It makes this connection available through the Application(“Conn”) variable. We could make it the responsibility of each page that needed database access to create its own connection and open it, but this is a time-consuming process and it is best to minimize the amount it is done. By storing an open connection in an Application variable for the entire website, we have a single connection that any page can interact with to get data from or send data to the database. Note that this strategy will work fine where there is a single web server at work, but in a very large ASP application that used a ‘server farm’ (a set of servers that can all process HTML and ASP page requests to the same site), we would need to provide an active connection for each server to prevent problems with two or more pages trying to work a single connection object simultaneously. Application_OnStart() also sets a session timeout of 20 minutes. This is the time that a session’s state will be maintained without page requests, before IIS shuts it down.
Application_OnEnd() undoes the work of Application.OnStart() by closing the database connection and destroying the connection object. The Application object will keep the connection open while requests are coming in, but once every session that the application supports has closed or times out, an open connection sinple takes up memory for no purpose. Application_OnEnd() is executed automatically when IIS has determined that the application is currently idle.
Session_OnStart() is executed at the start of each new session, and helps to keep track of that session (separately from any others that may currently be active). In it we set up two session variables – Session(“ClientID”), which is retrieved from a client-side Cookie and which may be null, and Session(“ReturnTo”) which will be a useful way of keeping track of the page a user is currently on if we need to direct them away from it to log-in to the system. In addition to these functions, which are best performed for the Application as a whole and for specific Sessions, there are a number of functions that we can consider to be general enough to merit making them available throughout the website. The standard way of doing this is to place Subroutines and Functions into a special code file called an include file. As its name suggests, we can include the code in this in any ASP file we wish, so making the functions available to it.
DHFunctions.inc
<% '************************************************** '*** GetConnectionString function '************************************************** '*** Written 9/5/2004 '*** Author: A.McMonnies '*** Revision 2.1 '*** Purpose - Function returns a string specifying '*** a full connection string for opening an Access '*** (JET 4.0) database in the same folder as the '*** page the function is run from. '======'*** Input parameter - db As String - name of MDB '*** database file. '*** Result - Connection-String As String '*************************************************** Function GetConnectionString(db) GetConnectionString = "PROVIDER=Microsoft.Jet.OLEDB.4.0;" & _ "Data Source=" & Server.MapPath(db) & _ ";Persist Security Info=False" End Function
'************************************************** '*** GetClientName function '************************************************** '*** Written 19/5/2004 '*** Author: A.McMonnies '*** Revision 1.0 '*** Purpose - Function returns a string containing '*** client's name '======'*** Assumes a connection is already made '======'*** Input parameter - id - a string of clientNo '*** Returns Client's name. '======Function GetClientName(id) Dim RS Set RS = Application("Conn").Execute("select fName + ' ' + _ lName as Name from Client where ID=" & id) If Not RS.EOF Then GetClientName = RS("Name") Else GetClientName = "Client no " & id & " does not exist" End If RS.Close Set RS = Nothing End Function
'************************************************** '*** GetStaffName function '************************************************** '*** Written 19/5/2004 '*** Author: A.McMonnies '*** Revision 1.0 '*** Purpose - Function returns a string containing '*** staff member's name '======'*** Assumes a connection is already made '======'*** Input parameter - staffNo - a string of staffNo '*** Returns Staff member's name. '======Function GetStaffName(staffNo) Dim RS Set RS = Application("Conn").Execute("select fName + ' ' + _ lName as Name from Staff where staffNo='" & staffNo & "';") If Not RS.EOF Then GetStaffName = RS("Name") Else GetStaffName = "Staff no " & id & " does not exist" End If RS.Close Set RS = Nothing End Function
'************************************************** '*** RSToHTMLTable function '************************************************** '*** Written 9/5/2004 '*** Author: A.McMonnies '*** Revision 1.0 '*** Purpose - Function returns a complete HTML '*** table as a text string. Table content is all '*** of the data from a ADO Recordset. First row '*** is column (field) names, followed by one row '*** per record for the full table. '*** If table has an 'ID' column, a 'link' param '*** -eter can be supplied to specify the URL of '*** a linked ASP which will be sent the ID as a '*** GET parameter. '*** NOTE - use SQL AS syntax to set column names. '*** e.g. SELECT CustName As Name FROM.... '======'*** Input parameters '*** 1. RS As Recordset - an ADO recordset which is '*** currently open. '*** 2. borderwidth As Integer (normally a small '*** integer value - 1 or 2. '*** 3. URL of an ASP for accessing individual '*** records from the table (i.e. a detail view '*** page. Only to be used if the table in RS '*** has an ID field. '*** Result - HTML Text As String '*************************************************** Function RSToHTMLTable(RS, borderwidth, link) Dim TBL, i ' Response.Write "
" & link & "
" ' Generate a HTML Table from the recordset data... TBL = "" & fld.Name & " | " Next If link<>"" Then F = F & "Select | " End If TBL = TBL & F & "
---|---|
" & fld.Value & " | " Next If link<>"" Then F = F & "View Detail | " End If TBL = TBL & F & "
'************************************************** '*** GenerateDateOptions function '************************************************** '*** Written 19/5/2004 '*** Author: A.McMonnies '*** Revision 1.2 '*** Purpose - Function returns a complete HTML '*** tag set for an option button with a range of '*** dates pre-loaded. This HTML should be embedded '*** in a form for user-input. '======'*** Input parameters '*** 1. StartDate As String - date at start end of range. '*** 2. EndDate As String - date at end of range. '*** Result - HTML Text As String '*************************************************** Function GenerateDateOptions(StartDate, EndDate) Dim HTML Dim Q Q = Chr(34) HTML = "" GenerateDateOptions = HTML End Function '************************************************** '*** GenerateHourOptions function '************************************************** '*** Written 13/6/2004 '*** Author: A.McMonnies '*** Revision 1.0 '*** Purpose - Function returns a complete HTML '*** tag set for an option button with a range of '*** hour-intervals pre-loaded. This HTML should '*** be embedded in a form for user-input. '======'*** Input parameters '*** 1. startHour As String - hour at start end of range. '*** 2. endHour As String - end at end of range. '*** Result - HTML Text As String '*************************************************** Function GenerateHourOptions(startHour, endHour) Dim h, options Dim Q Q = Chr(34) options = "" GenerateHourOptions = options End Function %> Listing 14: The DHIncludes.inc file – functions and subs for general use by ASP files. DHIncludes.inc is an include file that we refer to at the top of any ASP file we wish to incorporate its functions into. To make the functions in the file available, we use the following statement in an ASP file (note – DHFunctions must be in the same folder):
Now we can call any of the functions within this file from our ASP file. The utility functions in here are:
Function GetClientName(id) – this function retrieves the full client name from the database given the ClientID. We can incorporate a call to it within ASP code, like: Response.Write GetClientName(3) which would display the name of the client with ID = 3 in the Client table of the database, or can even incorporate it directly into a HTML statement:
Hello <%=GetClientName(Session("ClientID"))%>. Nice to see you back.
Function RSToHTMLTable(RS, borderwidth, link) – this very useful function will display the entire contents of an ADO Recordset within a HTML table. On the potentially many times you wish to display the information retrieved from a database in a Recordset, simple call this function passing the Recordset into the function as the first parameter, a number (0, 1 or 2 is normal) for the second parameter, and, if you wish each record in the table to display a link to a page to show the data in more detail, the name of the ASP file to do the detail display in the third. The function displays the table with headings taken from the Field names in the Recordset, so for example, a Recordset that was created with the SQL statement “select Name, email from Client” would be displayed as a two column table with headings “Name” and “email”. You can take advantage of the SQL ‘as’ clause to define the headings you wish to be displayed. For example, given the Client table in the DreamHome database, the SQL statement: select FName + ‘ ‘ + LName as Name, telNo as Telephone, email from Client; could be incorporated into an ASP file with a statement like: Response.Write RSToHTMLTable(RS, 1, "") This would display the data selected with the headings, Name, Telephone and email as follows:
Name Telephone email Fred Flintstone 555 1234 [email protected] Wilma Flintstone 555 1234 [email protected] Albert Johnstone 555 6677 [email protected] Clark Kent 555 9999 [email protected] Joe Bloggs 123 4567 [email protected] Edward Scissorhands 123 4567 [email protected] Albert Enistein 555 6789 [email protected] Snorrie Sturrluson 333 4567 [email protected] Ferdinand Oblogiotta 123 5555 [email protected] Joe Schmoe 123 45678 [email protected] Bill Gates 123 5555 [email protected] Ermentrude Llama 000 2222 [email protected] Table 1: Results from the RSTOHTMLTable function in DHIncludes.inc If the third parameter is included, it should be the name of an ASP file in the same folder as the one that uses the RSToHTMLTable function. This page should expect a single GET value – Request.QueryString(“ID”) – where ID is the ID column of a database table. The ASP page can then display more information about this particular record.
Function GenerateDateOptions(StartDate, EndDate) – this function will display a drop-down box (sometimes called a ComboBox) containing the specified range of dates. You should call this function within HTML form code to provide the client with a range of dates to select. Date entry is always a problem in software if the user has to type a date, particularly in web pages where an invalid date that is entered may be sent back to the server before it is recognised as an error. Users can enter an invalid date (such as 30th February), a date the past or even text that is nothing like a date, and if this is sent to the server, the result can only waste time and processing. Using the GenerateDateOptions function, you can ensure that the user is only able to enter a valid date from a selected range. The resulting date form a form can be picked up as Request.Form(“optDate”).
Function GenerateHourOptions(startHour, endHour) – this function will display a drop-down box containing a list of 1-hour ranges (e.g. 11:00 – 12:00) to allow a user of the site to select a time for an appointment. The resulting hour is a single number (the starting hour of the range) that can be picked up from Request.Form(“optHour”).
Now that we have set up the basic housekeeping for our active web site, we can think about what pages we will need to fulfil the functions listed earlier. Page name Purpose Links to Index.asp Display company information, and JoinMailingList.htm, list the available options. Note Rentals.htm, that these will be different for ReviewViewings.asp visitors depending on whether they are on the mailing list or not. This page can also display contact details. Rentals.htm This page allows a visitor (whether Rentals.asp on the mailing list or not)to view Index.asp properties that meet some selected criteria (size, location, price etc.). This page does not need to be active, since forms are supported in standard HTML Rentals.asp This page displays the list of Index.asp rentals that matches the criteria ViewProp.asp entered into Rentals.htm. ViewProp.asp Returns details of a property Index.asp selected on the Rentals.asp page BookViewing.asp Login.htm Provides a form for entering log-in information. Again, this page does not need to be active. JoinMailingList.htm Provides a form for a new client to AddToMailingList.asp add their contact and other details Index.asp to. Again, this pages can be plain HTML AddToMailingList.asp Takes the information from the Index.Asp JoinMailingList form and enters it into the Client table of the database BookViewing.asp This will have a form for booking Index.asp a property viewing, but since it CreateBooking.asp will be accessed via the Rentals.asp page, it will need to be active so that it can identify the Client and the Property CreateBooking.asp This page will do the job of adding Index.asp a booking record (details entered at BookViewing.asp). ReviewViewings.asp This page will allow a registered ViewingComments.asp client (on the mailing list) to Index.asp examine the records of any viewings they have made, either to cancel the viewing or to make comments and/or rent the property. ViewingComments.asp This page will accept any Index.asp comments or a reservation to rent a property Table 2: The files in the Dreamhome website
Exercise 1: Index.asp - the Home page
In this page, we should be able to identify a client who has already registered with the site provided their browser supports Cookies. For requests from browsers that do not support Cookies, we will need to make it possible for a client to log-in to the site. When a Session commences here, we can set up a session variable, ClientID, to indicate whether we know the client or not, having first checked for a Cookie. Of course, we may have the client on the system but their browser does not support Cookies, in which case we need to treat the client as a newcomer anyway. The logic of the page is straightforward: If the ClientID session variable has a value Greet the user Display registered user site options Else Display standard (non-client) site options End If What is displayed depends on the value in Session(“ClientID”) (which will have been set up in the Session_OnStart() routine in Global.asa. If this is nothing, we will display only the standard options available to non clients. If there is a ClientID value, we can retrieve and display that client’s name so that the page can greet them, and then display the options available to registered clients: view properties for rent or display details of any property viewings the client has had in the past. If there is not a ClientID value, we will display the standard options: view properties for rent, join the mailing list and log-in as a client. This last option is necessary is case the person visiting the site is a client, but does not allow Cookies in their browser. Joining the mailing list will of course create a ClientID for a visitor so that their next visit to this page will display the client-only options. A small amount of ASP code performs this functionality… <%@ LANGUAGE = VBScript %>
DreamHome Estate Agents
<% ' Do we know this client... If Session(“ClientID”) <> "" Then Name = GetClientName(Session(“ClientID”)) Response.Write "Hello " & Name & "
" Response.Write _ "Welcome back to the Dreamhome website.
" Response.Write _ "" Response.Write "” & _ “Check your viewing appointments.
" Else Response.Write _ "" Response.Write "" End If %> Listing 15: The Index.asp file – recognising a client (or not). Given what we have already covered, the only notable features of this page are the statements that display hyper-links. For example: Response.Write _ ""Using this utility, we can now test the Index.asp page by setting various client ID’s and checking that the client’s name is displayed in the browser. Clearing the client ID, we can then test that Index.asp displays appropriate options for a new client.
Exercise 2: Rentals.htm – The form for indicating rental preferences
This file does not include any ASP code (as an HTML file, any code that it contained would be ignored by the server’s script engine). However, it does serve a very important purpose for an active website, since it defines a form that will collect user- input and send it back to the browser. The form code is as follows:
House Rentals
Select the criteria for your ideal home...
Listing 16: rentals.htm – This defines the form shown in Figure 12 The code in listing 16 defines a HTML form. In the form (shown in figure 12), there are two drop-down boxes for the user to select from, plus a pair of option buttons, a text box and a pair of buttons. A HTML form is created in HTML code using the tags. Since a form is usually required to have an action (in this case, to call up a specific ASP page), this is defined in the opening