Cutting Edge A Client-side Environment for ASP Pages
这是一个由微软提供的功能强大的ASP-HTML转换工具.它将常用的ASP脚本转换为HTML从而减轻服务器的负担
下面是官方的英文原版介绍资料
ASP is a Web technology that relies specifically on capabilities of Microsoft?Internet Information
Services (IIS). For this reason, very few commercial products have attempted to provide an ASP-to-HTML
converter. The problem with such converters is that you must work in conjunction with the Web server to
trigger the ASP parser and find the intrinsic objects available. When you double-click on an HTML page
from the Explorer shell, you simply ask the browser to retrieve and render the source code of the file.
However, when you double-click on an ASP file from Explorer, you cannot ask the browser to translate it
into HTML.
Practical Reasons for an ASP Converter
OK, so an ASP-to-HTML converter might not be the tool that thousands of programmers dream of every night.
However, I can envision at least a couple of scenarios where such a tool would be very handy. The first
scenario was mentioned by Robert Hess in the April 2000 Web Q&A column. Suppose you have several pages
that require some interaction with a database on a frequently visited Web site. Writing them as ASP pages
looks like the perfect solution. However, if the database is not very volatile and the page output is not
highly dependent on the user's input, you could easily resort to plain old HTML for better performance.
For example, a list of suppliers is probably the kind of data that you would update only a few times a
year. Why rebuild that list on the fly each time it's requested, when a static HTML page would incur less
overhead?
An ASP-to-HTML tool could be used as a kind of batch compiler for ASP pages. You write them as server-side
resources, and then when you realize they are not particularly dependent on runtime conditions, you can
transform them into static HTML pages with either the .asp or .htm(1) extension.
While I'm on the subject, let me point out a significant improvement in the management of scriptless ASP
pages that's available with IIS 5.0. Until IIS 4.0, all resources with a .asp extension were subject to
parsing, whether or not they contained script code. With IIS 5.0 this drawback has been eliminated as IIS
checks for ```
...
1An ASP-to-HTML converter would also be handy when you need to view ASP pages offline. For example, a
2client recently asked me about the possibility of using a single development environment for building both
3Web sites and CDs. I first considered using static HTML pages that could be viewed over the Web or in a
4local browser, but the idea was soon dismissed given the complexity and the amount of content involved.
5Also, my client could not guarantee any particular software configuration on the user's machine, and the
6only product that could be supplied with the CDs was Microsoft Internet Explorer or a custom Web browser.
7ASP looked like the natural choice for the Web side of the project, but what about the CD? To make ASP
8work offline without a Web server, you need code that extracts all the ```
9…
10``` code blocks from the page
11and processes them. In addition, this module would have to provide a simulated ASP object model and take
12care of collecting the portions of plain HTML text. Then it would have to put it all together, combining
13the static HTML code with the output of the processed scripts.
14In this column, I will discuss the architecture of the offline ASP viewer and some implementation details.
15In particular, I'll show you how to emulate the behavior of the ASP Response object. Next month, I'll
16finish up the code, covering Request and Server plus some other related topics. This month's code shows
17the potential of this approach and works with typical ASP pages, though it is not comprehensive. I won't
18cover other ASP objects such as Session or Application because they are rarely needed in local scenarios.
19
20
21The Browser's Role
22To emulate ASP while working offline, you need a little help from the browser. Basically, the browser must
23be able to detect whether the page to which it's about to navigate is a URL or a local path name and
24whether it contains the .asp extension. If the user is calling a URL, the browser does what it would
25normally do. Otherwise, it calls a custom module to locally parse the content of the ASP file.
26Furthermore, the browser is involved when the ASP page that will be emulated contains forms and
27hyperlinks. (I'll discuss this further next month.) Given these requirements, to deal with ASP pages
28offline you need a customized version of the browser. While subclassing Internet Explorer or Netscape
29Communicator is always possible, I suggest you write a brand new browser from scratch using existing Web
30browser technology such as the Microsoft WebBrowser control. While I'll use Visual Basic?here, you can
31also use C++. As a good starting point in C++, you can try the MFCIE or ATLBrowser samples, both of which
32come with the latest Platform SDK. In Figure 1 you can see the layout of the browser. For illustration,
33I've divided the client area into three blocks: one for the actual HTML rendering, one for the original
34ASP text, and one for the expanded HTML text. Figure 2 shows the code for the browser.
35
36Figure 1 The Custom ASP Browser
37
38During the form's initialization, a new CAspParser object is created and set to work properly. Once you've
39clicked the Go button, the browser detects whether you're calling the ASP page locally or over HTTP, and
40acts accordingly. All the logic is hidden in the CAspParser class, which exposes three public functions:
41Initialize, SetScriptControl, and ParseTextToFile. Initialize makes sure the scripting environment is
42properly initialized and ready to work. Through SetScriptControl, the class receives the working instance
43of the script environment (more on this later). ParseTextToFile parses the content of the given ASP file
44and creates an output stream. Basically, the parser reads the whole content of the ASP file into memory
45and then walks through it. It locates any occurrence of "```
46", then copies the text that precedes "<%" to
47the output buffer, and starts a new search for the closing tag, "
48```". The command text is extracted and
49processed separately. Any output is then appended to the response buffer.
50The script code in the body of an ASP page may contain references to the intrinsic objects that form the
51ASP object model. These well-known objects are listed in Figure 3. IIS is responsible for making these
52objects—plus two more: ASPError and ObjectContext—available in the script's namespace when the parser is
53about to process the content of the various code blocks. To obtain an ASP parser that works outside the
54Web server, you should provide a replacement for these objects, which means building a client-side ASP
55object model.
56
57
58
59A Client-side ASP Object Model
60One of the problems with Web applications is the inability to maintain state when working over HTTP. State
61is the ability to associate variables and objects with a particular user. A tool to store individual
62settings and resources can solve the problem. This is what the Session and Application objects provide,
63albeit at different levels. But you don't always need to implement this feature in a client-side ASP
64object model. In fact, a local ASP page is normally accessed by one user at a time and state management is
65a far less important issue.
66From the perspective of an offline ASP viewer, the key ASP objects are Response and Request because they
67provide the basic functionality that make a page interact with the rest of the world. Whether you need to
68implement all or a part of the standard methods and properties depends on your particular project.
69Although ASP is tightly integrated with IIS and Microsoft Transaction Services (MTS), and COM+
70environments, this doesn't mean that you cannot use a unified, yet ASP-based approach for the concurrent
71development of products that deliver content through different media (like the Web and CDs). Offline pages
72consumed without the intervention of the Web server are normally much simpler and don't need all the
73features of an online Web application. Based on my personal experience, I suggest you implement a minimal
74set of features (similar to those I discuss here) and then extend the set when your pages need to support
75extra ASP features.
76I deployed the first version of my project with only Response and Request objects. In particular, I only
77implemented the Write method of the Response object, and just for the HTML content type. Request only
78exposed the QueryString collection. In a second step, I added support for Response.End and the Request's
79Form and ServerVariables collections. Later, I also added some special features such as new environment
80variables and new offline-only objects, including Scripting.FileSystemObject.
81The key questions concern how you simulate the Response or Request object and how you run all the script
82code that an ASP file contains. To execute script code, you can either take advantage of the Microsoft
83Script Control—a downloadable component (see http://msdn.microsoft.com/scripting/), or use the raw
84Windows Script COM interfaces. For a primer, look at the Extreme C++ column in the August 1997 issue of
85Microsoft Internet Developer. Since I'm developing an application in Visual Basic, using the Script
86Control is the natural choice.
87
88
89The Script Control
90ScriptControl is an ActiveX?control without a user interface that wraps all the Windows Script interfaces
91needed for dialog with a script language parser. It has a Language property through which you select a
92language. VBScript and JScript?are the two usual options, but provided you have a compliant parser, any
93scripting language is fine. Francesco Balena covered the ScriptControl in detail in the July 1999 issue of
94MIND (see "Exploring the Microsoft Script Control"). Tobias Martinsson's article, "Active Scripting with
95PerlScript," in the August 1999 issue of MIND, explores the use of Perl with ASP.
96When it comes to using the ScriptControl you need to do three things: set up the language, add as many
97objects as you want to the script namespace, and execute the script code. In my special edition browser, I
98set the language to VBScript during the form load event. At the same time, I create instances of all the
99objects I want to be visible to the script engine at runtime. Named items visible to the parser at runtime
100is a concept that warrants further explanation. The whole set of named items forms the script's namespace.
101A Windows Script parser (such as the Microsoft parser for VBScript) receives a vocabulary of known names
102at startup. This dictionary contains the language's keywords and global resources such as variables,
103objects, and subroutines. Behind each name (such as MsgBox) there's a programmable entity—whether it is a
104parser-specific function or the method of a certain in-process COM object. You can add new names to this
105namespace. Better yet, the interface of the ScriptControl (and thereby the Windows Script programming
106interface) allows you to do this in a very handy way. Look at the following code snippet: Set
107m_objResponse = CreateObject("MyASP.Response")
108m_objScriptCtl.AddObject "Response", m_objResponse
109
110
111Through the AddObject method, the ScriptControl adds a named item called Response to the script namespace.
112From then on, it is considered a language item. Each call to this element is automatically routed to the
113COM object you specified as the second argument of AddObject. Those two lines are part of the
114CAspParser.Initialize method and m_objScriptCtl is the instance of the ScriptControl that is going to be
115used for script processing.
116Once you execute those lines, any script code you run through that instance of the ScriptControl
117recognizes Response as a keyword and uses MyASP.Response to work with it. It's a very common technique in
118scripting. Incidentally, this is the same technique that allows IIS to inject the true ASP object model in
119the scripting context of a server-side ASP page. This workaround also makes it possible for Windows Script
120Host (WSH) scripts to rely on a system-provided WScript object.
121
122
123Call in Action
124When the browser's main form is ready to parse and display the ASP code, it calls the ParseTextToFile
125method, which takes two file names: the source ASP file and the target HTML file. When the method returns
126successfully, the form simply navigates to the newly created local HTML page. The full source code of the
127CAspParser class is shown in Figure 4. Let's see how it works step by step on a very simple ASP page:
The value of X is ``` = X `````` The CAspParser class initializes the script control by setting the script language to VBScript (this is not strictly necessary since the ScriptControl already defaults to it), and adding a brand new instance of the MyASP.Response object to the namespace. The control then passes to the method ParseTextToFile. It receives the name of the ASP file, verifies it has an ASP extension, and reads in all of its content. I used the Scripting.FileSystemObject for clarity only (see Figure 4). Using the CreateFile API or other I/O technique could give you better performance. The string with all the ASP content is then parsed for ``` … ``` blocks. All the text outside of these markers is written to the Response object. It accumulates the text into an internal string buffer that emulates the stream where the real ASP Response object writes. In this way, the simulated Response object caches all the output, just as the real ASP Response does when buffering is on. Note that under IIS 5.0 buffering is on by default, while it was turned off by default in earlier versions of IIS. In Figure 4, the Response.Clear method is used to clear any buffered text that you accumulated through repeated calls to Response.Write. This Clear method plays exactly the same role it does in the real ASP object model you're used to on the server. Now let's have a closer look at the implementation of the simulated ASP Response object. To further illustrate the language neutrality of COM and to avoid the problem of writing objects in Visual Basic with the same method names as some language keywords (such as Write or End), I decided to write the MyASP objects using ATL and Visual C++? The implementation of the MyASP.Response object is straightforward (see Figure 5). The MyASP objects need to expose methods with signatures that match the way you're using them in your client-side ASP pages. If you're using the client-side ASP engine to work on specific client-only pages, then there's no particular reason for you to use a custom object that mimics the ASP's Response. You are better off writing a completely custom object with the programming interface you prefer. The need to mimic the signatures of ASP intrinsic objects arises when you're writing dual pages to be used on the Web as well as locally on a CD. When you invoke the Write method on MyASP.Response, the text you pass in is added to an internal member variable that's ready for return to the caller. This behavior mimics exactly what the ASP Response object does internally when buffering is on. The Clear method empties the buffer. MyASP also implements a property called ResponseBuffer that returns the current content of the output buffer. This property works in much the same way as the ASP Flush method. Each time you read it, its contents are cleared. IIS itself manages to send the transformed text to the browser via HTTP. Consequently, there's no need to make the internal buffer available to the scripts in the ASP page. In fact, the ASP Response object doesn't have a method or property (such as ResponseBuffer) that returns the text accumulated in the internal buffer. In this client-side emulation, the browser needs to get the transformed text from the object, and a property is more helpful than a subroutine like Flush. Finally, the End method sets an internal variable to false. This variable is exposed through the CanContinue property and is used to stop the loop that governs the parsing of the ASP text. As you can see, the programming interface of the MyASP.Response object is similar—but not identical to—the ASP Response object. The logic behind the two objects is shared to some extent, but it clearly differs as the working context of the client and server-side editions of Response requires. In Figure 6 you can see that both the custom browser and Internet Explorer render my simple page in the same way. If you open Explorer in the folder that contains the specified ASP page and double-click the item, in most cases Visual InterDev?will open because it is the program that is usually registered to edit ASP files. If you want to be able to double-click on ASP files and see their content, you could associate them with a program like Visual InterDev. However, remember that a generic ASP page might be using objects like Session or Application that the client-side parser doesn't support.
Figure 6 The Custom Browser versus Internet Explorer
Consider a page like the following, which is nearly identical to the previous one except for a
Response.End statement.
1<html>
2<body>
x=1
Response.Write "Hello, world!"
1<hr/>
Response.End
1The value of X is ```
2= x