CIS Logo SVC Logo

   Computing & Information Systems
   Department

 

Schoology Facebook        Search CIS Site      Tutorials

Cars App 3



Improvements


Here we look at our previous web app, larger e-commerce web app 2, and ask ourselves what is missing, what functionality we might want to add, what we can improve, etc. The main improvement that we make is to use a web service to find the tax rate and the amount of shipping for each order. Other possible improvements are also examined to some extent. Some of the ideas presented here are again adapted from the book .NET E-Commerce Programming by Mike Gunderloy and Noel Jerke, Sybex (2002).

Using a Web Service to Get Tax and Shipping Information



Overview

  • Our previous web app, larger e-commerce web app 2, contained fixed code to compute the shipping amount and tax amount for each order.
  • If the tax rules change or the company needs to change the way if calculates the shipping cost, the e-commerce app would have to be rebuilt in Visual Studio, even though it might be that only a few lines of code need to be modified.
  • The most flexible way to deal with this might well be to compute the shipping amount and tax rate in a web service. That way, if the rules for these computations change, only the web service would need to be rebuilt. The e-commerce app itself would be unchanged.
  • We will create a web service that looks up the tax rate based on the state where the customer resides and finds the shipping amount based on data in another table. However, even if either computation needs to be changed to use other inputs in the computation, this can still be handled by rewriting the code for the web service.

Database Preparations

  • Create a new SQL Server table called Tax that is designed as follows:
Column Name Data Type Length Allow Nulls
TaxNum Int 4 no
TaxState varchar 2 no
TaxRate float 8 no
  • Make TaxNum to be the key field.
  • Also set the properties shown at the bottom when in design view to make TaxNum an identity field so that the first value starts at 1, the next is 2, etc.
  • Set the default value for TaxRate to 0.0.
  • Then add the following data to this Tax table. Of course, you do not fill in the TaxNum values as the identity field values are automatically filled in.
TaxNum TaxState TaxRate
1 PA 0.06
2 VA 0.045
  • Follow the above 2 rows of data with rows for the other 48 states and DC (District of Columbia) each with tax rate of 0.0.
  • We assume here that our business operates in PA and VA and that customers only need to pay state tax if they live in one of these 2 states.
  • Next, create a table named Ship to hold shipping amount information.
  • Design this new table as follows:
Column Name Data Type Length Allow Nulls
ShipNum Int 4 no
ShipMin int 4 no
ShipMax int 4 no
ShipAmount money 8 no
  • Make ShipNum to be the key field.
  • Also set the properties shown at the bottom when in design view to make ShipNum an identity field so that the first value starts at 1, the next is 2, etc.
  • Set the default value for ShipAmount to 0.
  • Then add the following data to this Tax table. Of course, you do not fill in the ShipNum values as the identity field values are automatically filled in.
ShipNum ShipMin ShipMax ShipAmount
1 1 1 200
2 2 2 350
3 3 3 450
4 4 5 500
5 6 10 550
6 11 100 600
  • The idea, here, is that if the number of cars in an order is between the min and max (or equal to either the min or max), then the shipping amount for this particular row is used.
  • Thus, a customer pays $200 shipping for 1 car.
  • A customer pays $350 shipping for 2 cars.
  • The shipping on 3 cars is $450.
  • The shipping for either 4 or 5 cars is $500.
  • The shipping for 6, 7, 8, 9, or 10 cars is $550.
  • The shipping for 11 through 100 cars is a $600 for all of them.
  • Of course, our company can charge shipping in any way it likes. We might prefer to have a set amount per car, in which case our web service would not need a Ship table as it could just take the number of cars times the standard shipping amount per car. Some other formula could be used to calculate shipping if we would want that.
  • We also need to make a couple of stored procedures since our web service will use them to get the appropriate data from the above tables.
  • In Enterprise Manager create a stored procedure called GetTaxRate that uses this code:

CREATE PROCEDURE studentc.GetTaxRate
    @TargetState varchar(2)
AS
SELECT TaxRate FROM dbo.Tax WHERE @TargetState = TaxState
GO
  • Also give the appropriate user (perhaps the SQL user) exec access to this stored procedure.
  • Then make another stored procedure containing the following code and name it GetShipAmount.

CREATE PROCEDURE studentc.GetShipAmount
    @NumPurchased int
AS
SELECT ShipAmount FROM dbo.Ship WHERE ShipMin <= @NumPurchased AND ShipMax >= @NumPurchased
GO
  • Also give the appropriate user (perhaps the SQL user) exec access to this stored procedure.
  • This stored procedure obviously finds the shipping amount in the correct row of the Ship table, that is, fromi the row whose ShipMin is less or equal to the number purchased and the ShipMax is greater or equal to the number purchased.

Changes in Visual Studio

  • First we create the web service.
  • For detailed information on web services, it is suggested that you read chapter 21 of the book Visual Basic .NET: How to Program, 2nd ed., by H. M. Deitel, P. J. Deitel, and T. R. Nieto, Prentice-Hall (2002).
  • In Visual Studio select File, New, Project, Visual Basic Projects, ASP .NET Web Service. Fill in a sensible location, such as https://cis3.stvincent.edu/studentc/TaxShip and click OK.
  • In Solution Explorer, click on Service1.asmx, wait a second and click on it again. This should allow you to rename this file. Name it StoreServices.asmx.
  • Use View, Server Explorer so that you can see Server Explorer in Visual Studio.
  • Expand the Data Connections item if need be.
  • Expand the item for your particular connection to the SQL database. For example, it might be something like CIS-W2KSERVER.studentc.studentc.
  • Find the entry under this for the GetShipAmount stored procedure and drag it onto the form for your web service.
  • It will place an SqlConnection object with the default name of SqlConnection1 on the form and an SqlCommand object name SqlCommand1. Rename SqlCommand1 (by selecting it and finding the name field under Properties) so that the new name is cmdGetShipAmount.
  • Next, drag the GetTaxRate stored procedure from Server Explorer to your form. It will use the same SqlConnection1 but will an SqlCommand. Rename the latter as cmdGetTaxRate.
  • Close Server Explorer to get it out of the way.
  • At this point, you should see approximately what is shown in this screen shot of the web service form.
  • Right click the form and select "View Code". This takes you to the code-behind file, which is where most of your work is done in creating a web service.
  • There will be some automatically-generated code present. Do not change it.
  • Near the top of the file, change the name of the class to StoreServices.
  • Change the namespace to something reasonable, such as http://cis3.stvincent.edu. The namespace is used to group web services. It does not have to be an actual URL on a web server.
  • Create the 2 methods shown below. Note where they fit into the overall layout of the code-behind file.

Imports System.Web.Services

<System.Web.Services.WebService(Namespace:="http://cis3.stvincent.edu")> _
Public Class StoreServices
    Inherits System.Web.Services.WebService

Web Services Designer Generated Code

    <WebMethod(Description:="Calculate the shipping amount on NumPurchased items")> _
    Public Function GetShipAmount(ByVal NumPurchased As Integer) As Decimal
        ' Call the GetShipAmount stored procedure to do the work:
        Try
            cmdGetShipAmount.Parameters("@NumPurchased").Value = NumPurchased
            SqlConnection1.Open()
            GetShipAmount = CType(cmdGetShipAmount.ExecuteScalar, Decimal)
        Catch exception As Exception
            GetShipAmount = 0.0   'Free shipping if our code fails!
        Finally
            SqlConnection1.Close()
        End Try
    End Function

    <WebMethod(Description:="Return the tax rate to use for state TargetState")> _
    Public Function GetTaxRate(ByVal TargetState As String) As Double
        ' Call the GetTaxRate stored procedure to do the work:
        Try
            cmdGetTaxRate.Parameters("@TargetState").Value = TargetState
            SqlConnection1.Open()
            GetTaxRate = CType(cmdGetTaxRate.ExecuteScalar, Double)
        Catch exception As Exception
            GetTaxRate = 0.0   'No tax if our code fails!
        Finally
            SqlConnection1.Close()
        End Try
    End Function
End Class
  • Essentially we have set up 2 procedures, GetShipAmount and GetTaxRate, that are accessible over the web.
  • There are no surprises in the VB code inside these procedures. They each call one of our stored procedures to find the information that is needed.
  • The Description is optional, but it should usually be supplied as it is helpful to those who might want to use your web service.
  • Use Build, Build Solution to finish the creation of your web service.
  • In a browser go to the URL for your StoreServices.asmx file. For example, the URL might be http://cis3.stvincent.edu/studentc/TaxShip/StoreServices.asmx. You might also use https instead of http.
  • This should show links for the 2 procedures we created above as well as the descriptions for each. You can try the links to see what they show you.
  • Next we do File, Close Solution to get out of the web service solution in Visual Studio.
  • Then open your cars2 project from the web server.
  • Use Project, Copy Project to create a copy called cars3.
  • Then open the cars3 project from the web server.
  • To use our web service in cars3 we need to add a web reference to the web service.
  • Use Project, Add Web Reference and fill in at the URL box the URL used above, such as https://cis3.stvincent.edu/studentc/TaxShip/StoreServices.asmx.
  • In the "Web References Name" box, fill in something that makes sense, such as cis3.stvincent.edu.
  • Click the "Add Reference" button.
  • Open the payment.aspx.vb code-behind file. (If necessary, open the payment.aspx form, right click on the form, and select "View Code".)
  • Change the IF test inside the first Try...Catch construct of the Page_Load procedure so that it uses cars3 instead of cars2, which would no longer make sense.
  • This section of code should then read something like this:

If (LCase(Request.UrlReferrer.AbsoluteUri) <> _
    "http://cis3.stvincent.edu/studentc/cars3/shipping.aspx") _
    AndAlso (LCase(Request.UrlReferrer.AbsoluteUri) <> _
	"http://cis3.stvincent.edu/studentc/cars3/payment.aspx") Then
    Response.Redirect("cart.aspx")
End If
  • To use the procedures in our web service is now easy.
  • First, in the Page_Load procedure put the following line along with the other Dim statements. Be sure to use whatever you called your web reference followed by a dot and the name of your web service.

Dim TaxShip As New cis3.stvincent.edu.StoreServices
  • In the same Page_Load procedure change the lines of code that calculate Shipping, Tax, and Total and then save these into the session state. Change these lines of code to the following:

Shipping = TaxShip.GetShipAmount(Quantity)
Tax = TaxShip.GetTaxRate(Session("State")) * Subtotal
Total = Subtotal + Tax + Shipping
Session("Shipping") = Shipping
Session("Tax") = Tax
Session("Total") = Total
  • The only differences in the code are that we now call the GetShipAmount procedure of our TaxShip web service, with the quantity of cars ordered as the parameter, to calculate the shipping amount and we now call the GetTaxRate procedure of our web service, with the state abbreviation as the parameter, to get the tax rate to use.
  • Save your files and rebuild your cars3 app.
  • Test it to see that it works correctly. In particular, look at the data in the relevant tables to see that the added rows for any test purchases are correct.
  • Once you are sure that your e-commerce app is working correctly, you can make some final changes to your web.config file if its settings differ from the following:
    • Set debug="false" as that will leave out debugging symbols, thus producing a smaller, faster app.
    • As usual, use customErrors mode="RemoteOnly" since that will prevent would-be attackers from getting detailed error messages should they find a way to crash your app.
    • Also check that you have trace enabled="false". We don't want trace logging in a completed app.
  • If you made any changes to web.config in the section just above, then rebuild your app.

Other Additions, Improvements

  • The above use of a web service is the only change that we carry out in detail here.
  • The following list gives suggestions for further changes but does not usually give the code needed to carry these out.

Sending an Order Confirmation Email

  • Usually you want your e-commerce app to send an order confirmation to the shopper by way of email.
  • To do so, you would use something like the following code. This code would go in the Page_Load procedure for payment.aspx.vb, just before redirecting the shopper to the confirmation web page, confirm.aspx. This Response.Redirect is probably the last line of code in your payment.aspx.vb code-behind file.
  • Whether of not you will be able to send this email depends on whether or not your server has been configured to send email.

Dim Message As New MailMessage 'Requires "Imports System.Web.Mail" at top of this file
Message.From = "sales@carcrazyusa.com"
Message.To = Session("Email")
Message.Subject = "CarCrazyUsa.com Order Confirmation"
Message.Body = "This is your order confirmation from CarCrazyUsa.com" & vbCrLf & vbCrLf & _
    "Order Number = " & Session("OrderNum") & vbCrLf & _
    "Subtotal = " & Format(Session("Subtotal"), "Currency") & vbCrLf & _
    "Shipping = " & Format(Session("Shipping"), "Currency") & vbCrLf & _
    "Tax = " & Format(Session("Tax"), "Currency") & vbCrLf & _
    "Total = " & Format(Session("Total"), "Currency") & vbCrLf & vbCrLf & _
    "Use the Contact page to reach us if you have questions about your order." & vbCrLf & _
    "Be sure to include your order number." & vbCrLf & vbCrLf & _
    "Thank you for shopping at CarCrazyUsa.com!"
SmtpMail.Send(Message)
  • Notice the comment in the code. You need to add a certain imports statement at the top of payment.aspx.vb.
  • The shopper's email address is extracted from the session state and put into the To field for the message.
  • Similarly the order ID number, subtotal, shipping, tax, and total are looked up in the session state and placed into the body of the email message.

Management Application

  • Our e-commerce app assumes that there is a separate management app for doing many of the things that those who operate our business need to do.
  • This probably includes checking each shopper's credit card information, processing each order, removing old credit card information (and perhaps other old information) from the database, adjusting product information in the database, etc.
  • Such a management application might be a Windows app or a web app. Especially if it is a web app, then good security is needed so that only the real managers of the store can access it.
  • Chapters 10, 11, and 12 of the Gunderloy and Jerke book show in detail how to write such a management app.

Automated Processing of Credit Card Data

  • An alternative to manually processing credit card data is to automate as much of this as possible.
  • Gunderloy and Jerke's book includes these suggestions in chapter 8:
    • Using checksum computations to weed out invalid credit card numbers.
    • One easy one is to check the credit card's expiration date to be sure that it is after the current date.
    • You can use a commercial tool such as PayFlow from VeriSign to validate the credit card data right when the e-commerce app receives it. This software sends you (the e-commerce company) and the shopper an email message saying whether or not the credit card transaction was approved. If you (or your e-commerce app) decides to accept the transaction, the appropriate bank credits your Internet Merchant Account with the correct amount.
    • Similar tools are supplied by VeriFone.
    • There are also tools for checking for fraudulent credit card numbers.

User Profiles

  • Each user's profile might store the person's contact information such as address, phone number, and email address.
  • A user must supply the correct email address and password to access the profile or have the appropriate cookie from our e-commerce site for quick access to the profile.
  • It is typical to allow the user to request a change of password if the person has forgotten the current password. The new password is emailed to the known email address of the owner of the profile. That way the new password goes to the true owner of the profile and not someone trying to break into another person's profile.
  • Once access is granted, the user can modify the data that is kept there.
  • The profile can be used to automatically fill in the shopper's contact information when doing a new purchase.
  • It can also be used to retrieve the last shopping basket for this shopper if the basket was not purchased. Perhaps the user now wants to complete the purchase.

Other Possible Improvements

  • Security is important at various levels in order to protect your e-commerce site from those who would steal credit card information, etc. See the online article E-Commerce Sites Forced To Adopt Security Standards.
  • Order status and order history information could be available to the shopper, perhaps under the profile page or perhaps on a new page that is accessible when the correct email address and password are entered.
  • Promotions, sales, and ads targeted to specific customers could be incorporated into the e-commerce app.
  • The option of having different shipping and billing addresses is important to some users. Our e-commerce app used a single address simply to keep the example shorter and not because a real e-commerce app should do this. It is also wise to allow the shopper to copy the shipping address to the billing address during the checkout process, as this can save time for many users, yet can be turned off for users who need different addresses.
  • Of course, add your own improvements as well!
Back to the main page for ASP .NET Web Apps

Author: Br. David Carlson
Last updated: October 12, 2008
Disclaimer