Page #79 (Chapter 11 - Using ActiveX DLLs from WebClasses)

Chapter 11 - Using ActiveX DLLs from WebClasses

Visual Basic Developers Guide to ASP and IIS
A. Russell Jones
  Copyright 1999 SYBEX Inc.

Building a Browser-Based Code Repository
I've included many small projects in this book that show how to use WebClasses. Now it's time to put all this information together. In this project, you'll build a browser-based code repository. The project stores titles and code in an Access database. As always, remember that you can download the code from the Sybex Web site.
  Note To download code, navigate to http://www.sybex.com. Click Catalog and search for this book's title. Click the Downloads button and accept the licensing agreement. Accepting the agreement grants you access to the downloads page for this book.
Techniques Included in the CodeRepository Project
The CodeRepository project includes most of the techniques you've seen in this book, including:
  HTML templates
  Custom WebItems
  Custom events
  Frames
  Redirection
  CStoredRecordset and CStoredDictionary
  External ActiveX DLLs
  ADO and the ADO wrapper functions, including stored procedures
  State maintenance
  ActiveX object persistence
There are two tables, called Users and Repository, in the database for this project. Figure 11.2 shows the structure of the database.
The Users table holds information about the people who use the application. The Repository table holds information about the code and code fragments placed into the repository. You can determine the usefulness of any database by testing whether it can answer the questions you need to know about the data. For example, this program needs to be able to list code entered by date, by user, or that contains a specific word or phrase. Administrators need to be able to find, list, and edit any user.
Each user must register before using the program. After new users register successfully, they receive Guest permissions. There are three levels of user permissions: Guest, Author, and Administrator:
Guests  Can view and search for code, but cannot change the code
Authors  Can view and search for code, as well as add and edit code
Administrators  Have full permissions and can also change any user's permission level
  Tip The database initially contains three sign-ons (you can create your own as well). None of the sign-ons require a password. The sign-ons are admin, author, and guest. They have appropriate permissions assigned. You can use them to explore how to limit program functionality based on permissions levels.
I implemented the project in three imperfectly separated layers:
WebClass  Displays and formats data. In some instances, the WebClass retrieves data directly from the data services layer.
CUser and CCode classes  Retrieve data from the data services layer.
CRepositoryData class  The data services layer. This class handles all database operations for the project.
The WebClass obtains data about individual users and code records from the CUser and CCode classes, which in turn retrieve the data from the CRepositoryData class. The WebClass retrieves lists of users and code directly from the CRepositoryData class. As written, the CUser and CCode classes are part of the main project, but you could easily remove them. If you do that, you should add a CList class to retrieve the lists.
The project uses 10 HTML templates that handle most of the display for the site. The WebClass handles administration functions separately via a custom WebItem.
Users must sign on to enter the application. The WebClass redirects unauthenticated requests to the sign-on page. The sign-on process follows much the same track as you saw in the SecuredSite project in Chapter 5, "Securing an IIS Application," with a few alterations due to state maintenance. Figure 11.3 shows the CodeRepository project's sign-on page.
When a user signs on, the sign-on code creates an instance of a CUser object (mUser) that represents the authenticated user. The CUser class contains public properties that correspond to the columns of the Users table in the database.
If mUser.InitBySignon(mConnectionstring, _
    Request("Signon")) Then
    If mUser.Password = Request("Password") Then
       Session("SignedOn") = True
    End If
End If
The WebClass stores and retrieves the mUser object for each subsequent request, using the CPersistor class you developed earlier in this chapter. The WebClass stores the mUser object during each WebClass_EndRequest event and re-instantiates it during the WebClass_BeginRequest event.
Private Sub WebClass_BeginRequest()
    If Not (Session("SignedOn") = True) Then
        If Request.Form("Signon") = "" Then
            Set NextItem = Signon
            Exit Sub
        End If
    ElseIf Session("SignedOn") = True Then
        Dim cp As CPersistor
        Set cp = New CPersistor
        If Not IsEmpty(Session("User")) Then
            Set mUser = cp.Depersist _
            ("mUser", Session("User"))
        End If
    End If
    mConnectionstring = Session("ConnectionString")
End Sub
  Note If you carefully trace through the WebClass_BeginRequest event, you'll notice that one of the problems with using frames is that the browser makes multiple requests to the WebClass—one for each frame. Using the two frames in this application doubles the amount of work the server must do to deliver the first frameset page. After the initial frameset display, the browser makes only one request for each content page. You should take this as a warning, though: Applications with multiple framesets make much heavier demands on the server and generate more network traffic than similar sites that use tables instead of frames.
Note that the WebClass does not attempt to store or retrieve an mUser object if the Session("SignedOn") variable has not been set to True. Therefore, unauthenticated or timed-out users cannot enter the site without signing on. To avoid an endless redirection loop, the WebClass checks the Request("Signon") variable. It does not redirect users if they are trying to sign on.
Private Sub WebClass_EndRequest()
    If Session("SignedOn") = True Then
        If Not mUser Is Nothing Then
            Dim cp As CPersistor
            Set cp = New CPersistor
            Session("User") = cp.Persist _
            ("mUser", mUser)
        End If
    End If
End Sub
Once authenticated, users see a frames page containing a menu and directions. In a "real" program, you could skip the directions page and jump directly to a code listing. The contents of the menu depend on a user's permission level. Figure 11.4 shows the menu and directions for an administrator.
In contrast, Figure 11.5 shows the menu and directions for a guest.
Figure 11.5: Menu and directions for a guest
All the links from the menu (left) frame display content in the contents (right) frame. You can't control the window in which content appears from the server; therefore, you must handle those issues on the client. Client-side (browser) code always controls the window in which content appears. Because the number of links in the menu is dependent on a user's permission level, the WebClass creates the links during the Menu_ProcessTag event. The Menu template contains a single replacement tag called <wcmenu>. The WebClass replaces that tag with the links appropriate to the authenticated user's permission level. Each link in the menu directs the browser to place the content in the contents frame using the target=<framename> syntax.
Private Sub Menu_ProcessTag(ByVal TagName As String, _
    TagContents As String, SendTags As Boolean)
    Select Case LCase$(TagName)
    Case "wcmenu"
        TagContents = "<a href='" & URLFor("Directions") _
        & "' target='contents'>Directions</a><br><br>"
        If mUser.UserType <> "G" Then
            TagContents = TagContents & "<a href='" _
            & URLFor("CodeEdit") & _
            "' target='contents'>Add Code</a><br><br>"
        End If
        TagContents = TagContents & "<a href='" & _
        URLFor("CodeList") & "' _
        target='contents'>List Code</a><br><br>"
        ' etc.
    End Select
End Sub
When a user clicks the List Code menu link, the WebClass retrieves a list of titles from the database and displays the list in the contents frame. Figure 11.6 shows a sample list.
Determining the interface for displaying large lists is one of the biggest problems in programming. For example, a display like the one shown in Figure 11.6 works extremely well when you have fewer than 50 items. As the list grows, displaying all the items becomes progressively less useful, and it is increasingly difficult for a user to find any specific list entry. Ordering the list can help, assuming the order that you provide is the one the user needs. Imagine that you had 10,000 items in the list. Displaying the title list would not only take a long time, but would make it difficult for a user to find an item. Certainly, you wouldn't want to scroll through thousands of items.
List display problems aren't limited to Web applications—they're common to all applications that deal with large lists. One way to help alleviate the problem is to let users search the list(s) for items that match desired conditions. Users can search the repository by clicking the Search Repository link on the menu frame. Figure 11.7 shows the search page.
Users can search either in the Notes field, the Code field, or in both fields for a single word or phrase. In a production program, you should extend this to allow Boolean and proximity searches as well. The application displays any matching records by title. Figure 11.8 shows the results of a search for the word complete in the Notes field. The search found one matching record.
Figure 11.8: CodeRepository search results
From any code listing, users can click on a title to view the code. Guests view code in read-only mode (see Figure 11.9).
In contrast, authors and administrators view code in edit mode. Figure 11.10 shows the same code in editable form.
Figure 11.10: Code Repository Author/Administrator code view
Appropriate buttons to update the changed code, delete the record, or cancel the changes appear below the editable code listing.
Administrators are the only people who can view and edit the registration information for other users. For example, an administrator may need to clear a forgotten password for an author. To edit a user record, an administrator clicks the Administration link in the menu, then selects List Users.
The Administer Users page (see Figure 11.11) shows the names of registered users. The program formats each name as a link. The administrator clicks a name to edit that user's registration information. The Edit User screen is similar to the Registration screen, but allows an administrator to set permission levels and delete users (see Figure 11.12).
The CodeRepository WebClass accesses all data through a CRepositoryData class exposed from an external ActiveX DLL called RepositoryData. Internally, the CRepositoryData class uses the ADO wrapping functions discussed in Chapter 10, "Retrieving and Storing Data in Databases," to open and close connections and retrieve data. Any errors that occur propagate back through the error-handling routines to the WebClass for display. Here are two example routines from the CRepositoryData class:
Public Sub deleteCodeByID(aConnectionString As String, _
       aCodeID As Long)
    Dim conn As New Connection
    Dim methodName As String
    Dim sd As CStoredDictionary
    methodName = Classname & "deleteCodeByID"
    On Error GoTo ErrDeleteCodeByID
    Call mADO.openConnection(conn, aConnectionString, _
       adModeReadWrite)
    Set sd = New CStoredDictionary
    sd.Add "CodeID", aCodeID
    Call mADO.executeSQL(conn, "deleteCodeByID", _
       adCmdStoredProc, sd)
    Call mADO.closeConnection(conn)
ExitDeleteCodeByID:
    Exit Sub
ErrDeleteCodeByID:
    Err.Raise Err.Number, Err.Source & ": " & _
    methodName, Err.Description & vbCrLf & _
    "Unable to delete the code with ID " & aCodeID & _
    " from the repository."
    Resume ExitDeleteCodeByID
End Sub
Public Function getUserBySignon(aConnectionString _
        As String, aSignon As String) As CStoredDictionary
    Dim R As Recordset
    Dim sd As CStoredDictionary
    Dim conn As Connection
    Dim methodName As String
    methodName = Classname & "getUserBySignon"
    On Error GoTo ErrGetUserBySignon
    Set conn = New Connection
    Call mADO.openConnection(conn, aConnectionString, _
        adModeRead)
    Set sd = New CStoredDictionary
    sd.Add "Signon", aSignon
    If mADO.getRecordset(conn, R, "getUserBySignon", _
        adCmdStoredProc, False, , , sd) Then
        Set sd = New CStoredDictionary
        Call sd.StoreRecord(R)
        Set getUserBySignon = sd
        R.Close
        Set R = Nothing
    Else
        Set sd = New CStoredDictionary
        Set getUserBySignon = sd
    End If
    Call mADO.closeConnection(conn)
ExitGetUserBySignon:
    Exit Function
ErrGetUserBySignon:
    Err.Raise Err.Number, Err.Source & ": " & _
    methodName, Err.Description & vbCrLf & _
    "Unable to retrieve the User with Signon " & aSignon _
    & " from the repository."
    Resume ExitGetUserBySignon
End Function
You can see that the routines are similar. The class has one peculiarity that I'll explain more fully in the next chapter; instead of having a ConnectionString property, you must pass a valid ConnectionString argument to every routine. Each routine opens a connection, performs one task, then returns data (if necessary) in a CStoredDictionary object (for single record results) or in a CStored-Recordset object (for multiple-record results).
Although this technique forces you to write more code, it also limits the number of round-trips to accomplish a task. For example, the WebClass typically calls only one of the methods in the CRepositoryData class for each request. If the class had a ConnectionString property, you would need to make two calls to the class, one to set the property and one to execute a method. With the ConnectionString argument, you need to make only one call.
In the next chapter, you'll see how to increase the scalability of the project by running the external RepositoryData DLL in MTS.



Visual Basic Developer[ap]s Guide to ASP and IIS
Visual Basic Developer[ap]s Guide to ASP and IIS
ISBN: 782125573
EAN: N/A
Year: 2005
Pages: 98

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net