Developing the Server Pages

The last step in the development of this example application is to create the ASP scripts that will allow the user to interact with the application. These scripts will use the methods provided by the application object that we have just created. To determine the scripts that need to be created, we will use an approach similar to the one we used when determining the functionality of the application component. By analyzing the steps that the user has to go through to complete the task of transferring funds, we can identify the pieces of data that the user interface must supply at any given time and identify those pieces of data that the user must provide.

If you remember from the assumptions that were made at the beginning of the example, the user is currently logged into the system and has passed through all of the necessary security checkpoints. If we now trace through the steps the user must follow, we can begin to see the different ASP scripts that are needed for the application.

From these steps, there looks to be 2 Active Server Pages script files that need to be created. One that will allow the user to select the accounts and the transfer amount. The second will be the script that actually performs the transaction, and then provides the response information to the user.

SelectAccounts.asp

This script will be used to allow the user to select the source account number, the destination account number, and the amount to transfer. To obtain the list of account numbers, it will use the ListAccounts method of the application object. Since this returns a comma-delimited string containing the list of accounts, the ASP script will need to parse this string to extract the individual account numbers. The user should be able to select the accounts for the transfer from a drop-down list. There will be some client-side validation code that will check to make sure that the account numbers for the source and destination are different. This will be called when the user attempts to submit the form.

The user will also be given a text box in which to type the amount for the transfer. This amount will be validated when the form is submitted to the server to ensure that the source has sufficient funds to make the transfer. If the funds are not sufficient, then the server will redirect the client back to this script.

<%
Option Explicit

dim custID
custID = 1

Since this is just an example, we are setting the customer ID to 1. In a real application, this value could either come from a form value, a URL parameter, or from a session-level variable.

dim bNSF 'Set to TRUE if page is being displayed due to insufficient funds
bNSF = False
dim srcAcct, destAcct, xferAmt
   
if Request.QueryString("src") <> "" then
   bNSF = True
   srcAcct = Request.QueryString("src")
   destAcct = Request.QueryString("dest")
   xferAmt = Request.QueryString("xfer")
end if

dim objBank
Set objBank = Server.CreateObject("BankExample.Bank")

The bNSF flag is used to indicate if this page is being displayed as a result of the user's selected source account having insufficient funds to perform the transfer. You will see in the Transfer.asp file how this is determined. The values that the user had selected for source and destination accounts, as well as the amount of the transfer, are passed back to this script as part of the URL. These values will be displayed as the default values in the form on this page. For now, the values are stored in temporary variables.

Since we will be generating a list of accounts, we will first need a reference to the application object. The 'BankExample.Bank' string is the name of our component as it appears in the system registry.

dim strAccounts
strAccounts = objBank.ListAccounts(custID)

dim arAcct(), iArraySize, iAcctNums
iAcctNums = 0
iArraySize = 5
redim arAcct(iArraySize)

The ListAccounts method of the Bank object is the called to return a list of accounts. The customer ID is supplied as a parameter. The return value will be a comma-delimited list of accounts, which will be parsed in the next step.

dim iPos, iSrch, strAcct
iPos = 1
iSrch = Instr(iPos, strAccounts, ",")
do while not iSrch = 0
   strAcct = Mid(strAccounts, iPos, iSrch-iPos)
   arAcct(iAcctNums) = strAcct
   iAcctNums = iAcctNums + 1
   if iAcctNums = iArraySize then
      iArraySize = iArraySize + 5
      Redim preserve arAcct(iArraySize)
   end if
   iPos = iSrch + 1
   iSrch = Instr(iPos, strAccounts, ",")
loop

The value that is returned from the ListAccounts method will be a string that looks something like this: "1234,6789,5432". This will need to be parsed into an array, so that the array can be used to build a drop-down list box. The parsing routine will sequentially move through the string location each comma. Each account number can then be extracted and stored in the arAcct array. This array is dynamically resized as needed. Rather than resizing the array every time a new entry is added, which would have a big cost in terms of performance, the array is increased in size by 5 each time it is resized.

strAcct = Mid(strAccounts, iPos, len(strAccounts))
arAcct(iAcctNums) = strAcct
iAcctNums = iAcctNums + 1

%>
<HTML>
<SCRIPT Language="JavaScript">

When we can find no more commas in the string, we still need to copy the final account number in the string. Since the end of the string, not a comma terminates this account number, it will not be caught by the parsing loop. This final account number needs to be added to the account number array.

We will be performing client-side validation of the form entry to ensure that three cases are not true.

This validation is done using JavaScript, rather than VBScript, so that the client browser can be any browser that supports JavaScript, rather than just Internet Explorer.

<!--
function sendForm() 
    {
      var xAmount;
        if (document.xfer.SourceAccount.value==document.xfer.DestAccount.value) 

Examining the value property of the SourceAccount or DestAccount member of the xfer form collection, which is all part of the document object, retrieves the values that were selected for the Source Account and the Destination Account. If the values are the same, then a JavaScript alert is shown to the user.

        {
            alert("You cannot transfer to the same account.");
         return;
        }
      xAmount = parseFloat(document.xfer.xferAmt.value);
        if (xAmount == 0.0 || isNaN(xAmount)) 

The value contained in the Transfer Amount field is converted to a float value by using the JavaScript parseFloat method. To check to see if there is a value entered, we check to see if the float value is 0 or if it is set to NaN. NaN is a JavaScript constant that indicates that the value could not be converted to a numeric value. If this is the case, then we alert the user, again using the JavaScript alert.

        {
            alert("You must supply an amount to transfer.");
         return;
        }
        if (xAmount < 0.0 ) 

Finally, if the amount is less than 0, we alert the user that they cannot transfer a negative amount. After each alert, this function returns to the caller. You will see when we get to the <FORM> tag how the form is prevented from being submitted. Finally, if all three validations are successful, then the form is explicitly submitted using the submit method of the form object.

        {
            alert("You cannot transfer a negative amount.");
         return;
        }
        document.xfer.submit();
    }
//-->
</SCRIPT>

<HEAD>
<TITLE>Account Transfer</TITLE>
</HEAD>
<BODY>

The bNSF flag indicates that the Source Account that the user selected does not have sufficient funds to complete the transfer. If this flag is set, then a message is displayed to the user that the transfer amount is too high and needs to be adjusted.

<% If bNSF then %>
<H2>Insufficient funds to complete transfer. Please adjust the amount.</h2>
<% End If %>
<FORM name="xfer" action="transfer.asp" method="POST" onSubmit="sendForm();return(false);">

The <FORM> tag will submit the results of this form to the Transfer.asp script file for processing. When the user clicks the submit button, the onSubmit handler is called. The handler will first call the sendForm function that was declared earlier. If this function returns, which means that the values selected did not pass the validation routines, then the onSubmit handler returns false. This action will prevent the form from being submitted, and allow the user to make changes to their entries.

<H3>Select an account to transfer from:&nbsp;
<SELECT name="SourceAccount">
<%
   dim iCnt
   for iCnt = 0 to iAcctNums - 1
      if arAcct(iCnt) = srcAcct then
%>
<option value="<%= arAcct(iCnt) %>" SELECTED><%= arAcct(iCnt) %>
<% Else  %>
<option value="<%= arAcct(iCnt) %>"><%= arAcct(iCnt) %>
<% End If %>
<% next %>
</SELECT>

The Source Account drop down list is created by going through each of the entries in the array of account numbers that was created earlier. If the account number is the same as the source account number then that value will be selected. This technique relies on the fact the VBScript initializes all variable to 0 or blank values. In the case where this page is being displayed without default values, then the value of srcAcct will always be blank, and therefore no option will be explicitly selected.

</H3>
<H3>Select an amount to transfer:&nbsp;
<% If bNSF then %>
<input type="Text" name="xferAmt" value="<%= xferAmt %>" size="10">
<% Else %>
<input type="Text" name="xferAmt" size="10">
<% End If %>
</H3>

The text box for entering the amount of the transfer is displayed next. If the insufficient funds flag is set, then the value that the user had previously selected is entered as the default value for the text box. Otherwise, this box is initially left blank. Next, the destination account drop-down list is displayed. This code is identical to the code to display the source account list.

<H3>Select an account to transfer to:&nbsp;
<SELECT name="DestAccount">
<%
   for iCnt = 0 to iAcctNums - 1
      if arAcct(iCnt) = destAcct then
%>
<option value="<%= arAcct(iCnt) %>" SELECTED><%= arAcct(iCnt) %>
<% Else  %>
<option value="<%= arAcct(iCnt) %>"><%= arAcct(iCnt) %>
<% End If %>
<% next %>
</SELECT>
</H3>
<input type="Submit" name="" value="Transfer Funds">

Finally a Submit button is displayed that allows the user to submit the form for processing. We could have also displayed a reset button that would have automatically cleared that values entered in the fields. For such a short form, this is probably unnecessary.

</FORM>
</BODY>
</HTML>

When this page is displayed in the user's browser, it will look like this:

Now that we have the page to gather the information for the transfer from the user, we need to create the Transfer.asp script. This script will perform the actual work to transfer the funds.

Transfer.asp

The Transfer.asp script is responsible for actually processing the funds transfer. The initial step that this script must perform is to check to see if the source account has sufficient funds to perform the transfer. If it does, then the script will withdraw the funds from the source account and then deposit the funds in the destination account. When this is completed successfully, a record of the transfer is written to the transaction log. When all of these steps have completed successfully, the transaction is committed. If any one of these steps fail, then the entire transaction is rolled back.

<%@ TRANSACTION=Required %>
<%
Option Explicit

dim objBank
Set objBank = Server.CreateObject("BankExample.Bank")

dim srcAcct, destAcct, xferAmt
srcAcct = Request.Form("SourceAccount")
destAcct = Request.Form("DestAccount")
xferAmt = Request.Form("xferAmt")

dim bSufficientFunds
bSufficientFunds = objBank.FundsAvailable(srcAcct, xferAmt)

This page will be a single transaction. To identify this, the TRANSACTION parameter is set to Required. This will force this page to participate in a transaction. Since a transaction cannot span multiple ASP script pages, a new transaction will have to be created to encompass this page.

A reference to the application object is created. The values that were submitted on the form from the SelectAccounts page are stored in local variables. Since these values will have to be accessed multiple times on this page, storing their values in local variables will allow for faster access times than having to search the Request.Form collection. It also makes the code more readable and concise.

The FundsAvailable method is called to check that the amount of funds requested for transfer is available in the source account. If this method returns False, then the user will need to change the amount or select a different source account. In the SelectAccounts.asp script, there is code to support this. We need to redirect the browser to display this page with the user's values. This is done by using the Response.redirect method, and supplying the values from the form as URL parameters.

if not bSufficientFunds then
   Response.redirect "SelectAccounts.asp?src=" & srcAcct & "&dest=" & destAcct & "&xfer=" & xferAmt
end if

%>
<HTML>
<HEAD>
<TITLE>Account Transfer</TITLE>
</HEAD>
<BODY>
<H3>Transfer in Progress</H3>
<HR>
<%
dim cWithdrawl, cDeposit, cTransRec, strError
cWithdrawl = objBank.Withdrawal(srcAcct,xferAmt)

The first step in performing the transaction is to withdraw the funds from the source account. The return value from this method will either be the amount that was withdrawn, or it will be an error. A string that begins with "ERROR" flags the error. We check to see if there was an error or if the amounts do not match. If neither of these are true, we can continue with processing.

The next step is to deposit the amount withdrawn into the destination account. At this point, if there were transaction fees that the bank wanted to apply, the amount of these fees could be deducted at this time.

Again, the return value of the Deposit method is checked to see if the amounts do not match or an error flag is encountered. If everything is successful, then the transfer is logged by using LogTransaction method.

if Left(CStr(cWithdrawl),5) <> "ERROR" or cWithdrawl <> xferAmt then
   cDeposit = objBank.Deposit(destAcct,cWithdrawl)
   if Left(CStr(cDeposit),5) <> "ERROR"  or cDeposit <> xferAmt then
      cTransRec = objBank.LogTransaction("TRANS", srcAcct, destAcct, xferAmt)
   else

This is the error handler for the Deposit method. If something happened that caused the method to fail, then the error message would be supplied in the return value. This is stored in a variable for later display to the user. The transaction is then explicitly aborted. While the Deposit method may have also aborted the transaction, there is no harm in having the script abort the transaction as well. All it takes is one part of a transaction signaling an abort to cause the entire transaction to be aborted.

      strError = cDeposit
      ObjectContext.SetAbort
   end if   
else

This is the error handler for the Withdrawal method. It is the same as the Deposit error handler, except it will store the result of the Withdrawal method for later display as an error.

   strError = cWithdrawl
   ObjectContext.SetAbort
end if

The results of the transaction are displayed for the user by handling the transactional events that are generated. If the transaction completes successfully, then the OnTransactionCommit event will be fired. The handler for this event will display a message indicating successful completion of the transaction, as well as a statement documenting the details of the transfer.

sub OnTransactionCommit()
   response.write "<H4>Transaction Completed Successfully</H4>"
   Response.write "<H4>" & FormatCurrency(xferAmt) & " transferred from Account #" & srcAcct & " to Account #" & destAcct & ".</H4>" & vbcrlf
end sub

If the transaction is aborted, then the OnTransactionAbort event will be fired. The handler will display a message that the transaction was unable to complete. The error message that was generated by the component that failed will be displayed for the user.

sub OnTransactionAbort()
   response.write "Unable to complete the transaction<BR>"
   Response.Write strError
end sub

%>
</BODY>
</HTML>

When the transaction completes successfully, you will see a page similar to this in your browser:

© 1998 by Wrox Press. All rights reserved.