This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links.
Client-side Environment for ASP Pages-Part 2 | |||||
Dino Esposito | |||||
Download the code for this article: Cutting1000.exe (101KB) Browse the code for this article at Code Center:Client-side ASP Browser |
|||||
ast month (September 2000) I gave you a quick tour of the script technologies you need to create a client-side environment that can execute ASP pages. I built a custom browser in Visual Basic® that is capable of processing ASP pages without Microsoft® Internet Information Services (IIS). This browser renders the HTML contained in an ASP page when you double-click on the ASP file. This information allows you to write ASP pages that are more versatile; they'll work both online and offline. When you're online, they run within the context of IIS and Microsoft Transaction Services (MTS) and COM+ and take advantage of the IIS features such as the ASP intrinsic object model and protected environment. When you're offline, you have access to a runtime enriched with simulated ASP objects that you can customize with other functionality. The Request Object In the original ASP object model, the Request object is the COM component that wraps all the data coming from the browser through HTTP POST and GET commands into a set of data structures. The Request object is also frequently used to retrieve special environmental variables through the ServerVariables collection. A client-side version of the Request object must expose at least the QueryString and Form collections. The QueryString contains the parameters sent through a GET command. The Form collection contains the parameters arriving from an HTML form via the POST command.
In a server-side ASP page, you retrieve those parameters through the QueryString collection of the Request object:
But what if you want to send a query string to a local ASP page? You must create a way for your offline environment to handle parameters sent along with the path:
The special browser I built last month is able to open an ASP page as a file and process its contents. Of course, if the ASP page contains unnecessary parameters, you should strip them before processing the page content. Furthermore, you should make the necessary parameters available through the QueryString collection of name/value pairs. The following VBScript code excerpt shows how to extend the ParseTextToFile method of the CAspParser class I introduced last month.
The ParseTextToFile method is invoked when the browser is called to navigate to a local ASP page. The argument (aspFile) is the ASP page name. As shown earlier, the path can be a sort of a hybrid: neither a fully qualified path name nor a regular URL.
is passed for further processing to a new procedure called ExtractHttpGetParams (see Figure 1). This subroutine splits the string into name=value pairs and stores them in the collection that the client-side Request object makes available.
Let's take a look at a simple ASP page to verify that all this really works in practice. Consider the following ASP page called request.asp:
This code dumps out all the name/value pairs stored in the QueryString collection. When called over HTTP with a query string like
it produces the output shown in Figure 3. As you can see in Figure 4, the result is identical in the offline browser. In both cases, the source code of the ASP page has access to a valid Request object that is capable of satisfying all of its requests. The Dictionary and Collection ObjectsIf you're using Visual Basic to implement the Request object, it might seem a natural choice to employ the native Visual Basic Collection object to code both the Form and the QueryString collections. Admittedly, this is exactly what I did when I first coded this object. The Visual Basic Collection object, though, is not a perfect reproduction of the ASP native collections. Using a Visual Basic Collection, you won't be able to get the name or the value of any particular item. You must use either an index or the specified key to retrieve a value. In other words, to populate a Visual Basic Collection you need code like this:
The Collection object is designed to be more of a flexible container for data than an associative array or a dictionary. The name or the key is only a shortcut to reach a certain item, it's not the actual data. There's no way for you to enumerate the names or keys available from a Visual Basic Collection. While this feature is supported by the ASP Request object, you need something else to simulate the behavior of Request locally. The answer is the dictionary object that Microsoft introduced with VBScript 3.0. The dictionary object is also available as a standalone component and can be downloaded from the Microsoft Web site as part of the Microsoft Scripting Runtime Library (https://msdn.microsoft.com/scripting). It is also part of the Windows® Script Host runtime and a native component of both Windows 98 and Windows 2000.
Note that now the name/key is the first argument of the Add method and is the one that the For Each enumerator retrieves by default. A dictionary object allows you to write and run the following code successfully:
To build a client-side Request object, you need to use the Scripting.Dictionary object to expose the Form, QueryString, and ServerVariables objects. In general, any ASP collection that you want to emulate must be coded through this dictionary or a programmatically equivalent object. HTML Forms Forms are a key element in the Web applications architecture, and you must be able to simulate them to make offline ASP a reality.
The foo.asp page will process all the information entered in the form's input fields. Whether these arguments will be available through the Form or the QueryString collection depends on the HTTP command you choose to issue the request. By default, the request goes through a GET command (QueryString), but if you set the form's method property to POST, the HTTP POST command is used and the arguments are available through Form. Since software isn't magic, the next natural question is who's responsible for filling either the Form or the QueryString collection? The answer is easy: IIS.
the string is
The code shown in Figure 6 demonstrates how a string like this is then split and inserted into either the Request's Form or QueryString dictionaries.
Set this variable with the current HTML document:
Now you're ready to handle all the events, such as the onclick event shown in Figure 6. Storing a reference to the parent window object during the DocumentComplete event helps to retrieve the source event object later.
At this point, it's easy to check the tag name and the type of the element that was clicked to start the DHTML event bubbling up to the document object.
Figure 7 HTML Post Working Offline Being able to manipulate forms offline is a significant benefit since most of the work you do on the Web, such as using search and registration pages, involves filling out forms and posting data to the server. In Figure 9, you can see a page built on these principles. The page allows you to query for articles by specifying the magazine and the year of publication. The same ASP page also works when viewed with the offline browser (see Figure 10).
The nLen argument represents the size of the buffer to be filled. Unlike several other Win32® APIs, GetUserName doesn't return the actual length of the string upon exit, but requires nLen to be passed by reference and modifies it. nLen must be a Long (32-bit, like a pointer), not an Integer, which is only 16-bit in Visual Basic. In addition, GetUserName sets nLen with the length of the string plus oneâ€"the terminating null character. You may think that GetComputerName, an API that you probably use in conjunction with GetUserName, would follow the same pattern for determining the actual size of the buffer. That's true, except that shortening the returned size by one actually truncates the buffer. The GetComputerName API doesn't add the final null to the count.
Now you can make decisions based on the working mode. For example, you could check the content of the custom OFFLINE variable. (When choosing a custom variable name like this, make sure it doesn't appear in the standard (server-side) set of environment variables.) The following code snippet addresses the creation of dual pages:
Repeatedly using the Request object might create unnecessary overhead. But thanks to the capabilities of the Windows Scripting interface (the Script control is only a wrapper built around those interfaces) there is another option. The Script control exposes a method called AddCode that allows you to import into the scripting context any piece of valid script code. In this way, you can import external files with handmade procedures, and you can also define some global variables, like this:
Given this, checking the working mode is as easy as using the following lines of code:
When you implement this approach, you no longer need the ServerVariables collection. Adding Custom COM ObjectsTo inject the simulated Response and the Request objects into the script, use the AddObject method of the Script control like I did here.
Likewise, you can add all the custom objects you want and make them natively available to the script. For example, suppose you want to extend the object model with the FileSystemObject component. With a couple of lines of code, you're finished.
You can choose any name you want to associate with the object's instance. In this case, FileSystem becomes a sort of keyword just like Response or Request. Figure 13 illustrates how you can use FileSystem to produce the result shown in Figure 14 (offline use) and Figure 15 (online use).
FileSystem is now a native component of the ASP object model that is used on the client side. ASP COM Components The final point I'd like to discuss concerns the use of ASP COM components. An ASP COM object is a COM component that can internally access the ASP intrinsic objects. Such a component must link directly to a type library that exposes the original IIS ASP objects.
This is a specific solution that works great with IIS 5.0 and ASP 3.0, but a similar approach using the ScriptingContext object has been available since IIS 3.0.
There's only one little drawback: you can't use the early-binding! Conclusion This month's source code contains the updated project for the ASP offline browser and the Visual Basic implementation of the Request object plus a bunch of sample ASP pages. To conclude this two-part series, let me recap the main points. Creating a client-side environment for ASP pages means writing a slightly customized version of the browser that handles navigation to local ASP pages as well as form submissions. The browser must be able to parse the ASP source code and process the script code block in a scripting namespace where valid instances of Request and Response objects are available. You can inject these simulated objects (and execute the script code) thanks to the services of the Script Control. Taking advantage of its programming interface, you can define new environment variables and extend the ASP object model with new objects. A typical example of this would be accessing the registry rather than a LDAP directory to authenticate a certain user. Once you've taken some extra measures to manage form submissions and the use of ASP COM components, there's nothing that prevents you from employing the same type of ASP technology to deliver content on the Web and on local media such as a CD. |
|||||
Dino Esposito is a senior trainer and consultant based in Rome. He has recently written Windows Script Host Programmer's Reference (WROX, 1999). You can reach Dino at desposito@vb2themax.com. |
From the October 2000 issue of MSDN Magazine.