Programming MicrosoftВ® OutlookВ® and Microsoft Exchange 2003, Third Edition (Pro-Developer)

In this section, we'll explore ASP technology. You should know about ASP for several reasons. First, most of your Collaboration Data Objects (CDO) or Active Directory Services Interface (ADSI) applications will run on the Web and use ASP. Second, most problems in Web applications stem from a lack of understanding of basic ASP concepts.

ASP Fundamentals

ASP pages are standard text files that contain HTML and script. The script can be written using any ActiveX scripting language, such as VBScript or JScript. The HTML files that most Web developers write differ from ASP files in two significant ways. First, instead of having an .htm or .html file extension, ASP files have an .asp file extension. When you include Microsoft Internet Information Services (IIS) as part of your installation, you also install an Internet Server Application Programming Interface (ISAPI) component that processes all files with an .asp extension. This ISAPI component parses the ASP file and executes the appropriate script. Second, the actual script is processed on the Web server. The processed results can include client-side scripting code, but for the most part the results are just simple HMTL. Returning only HTML is a big benefit: any modern Web browser can view the results of an ASP application.

Because ASP supports VBScript, you can easily move from developing Outlook forms to developing ASP pages. The only difference in the development process is that you should use the CDO library to write your ASP application rather than the Outlook object library because CDO is designed to be used in applications that will have multiple users and be run on a server.

The following code is an example of an ASP application. This example uses the VBScript function Now to print the date and time that the ASP application ran on the Web server.

<%@ LANGUAGE="VBSCRIPT"%> <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> <HTML> <HEAD><TITLE>ASP Example</TITLE></HEAD> <BODY> <H1>I was created on <%=Now()%></H1> </BODY> </HTML>

As you can see, the syntax of the ASP script is a little different from the syntax for Outlook code. To tell the Web server that you want to run a script on the server, you must enclose the script in special characters : <% and %> . ASP supports placing your script directly in your HTML code ”the script does not have to be in a separate section of the HTML file. If you run the same page on a server that does not have the proper ISAPI component for ASP, your code will look like only comments to that server. Also, with ASP.NET some changes have taken place. Your code is now separate from your HTML code to make coding easier.

Take a look at the first line of the code:

<%@ LANGUAGE="VBSCRIPT"%>

ASP assumes that the default language for server-side script is VBScript. If you replace VBSCRIPT with JSCRIPT , you can write server-side JScript code.

You might be wondering what the <%=Now()%> statement does in this example. The equal sign (=) indicates that the code should evaluate the expression, which in this case returns the current date and time. The equal sign in ASP is a shortcut for calling the Write method of the Response object.

Global.asa

If you've looked at the directories that contain .asp files, you might have noticed a file with the .asa extension: Global.asa. This is a special file in ASP applications that allows you to include code that executes when an application starts and ends and also when a session starts and ends. One thing to remember is that the Global.asa is an optional file for your Web applications. A skeleton Global.asa file is shown here:

<SCRIPT LANGUAGE="VBSCRIPT" RUNAT="Server"> Sub Session_OnStart 'Put your session startup code here End Sub Sub Session_OnEnd 'Put your session termination code here End Sub Sub Application_OnStart 'Put your application startup code here End Sub Sub Application_OnEnd 'Put your application termination code here End Sub </SCRIPT>

The Global.asa file contains stubs for your session and application start and end subroutines. To understand when these subroutines are called, you must understand what exactly constitutes a session and an application inside ASP.

When you browse Web pages, the Web server usually does not remember who you are or where you have been, and it does not store any values associated with you. One of the features of ASP is that it transforms the applications that you can build using the HTTP protocol from being stateless to being able to track the state of users. This ultimately lets you create global variables that are maintained for users throughout an application.

An ASP application consists of a virtual directory and associated files. But to understand when an ASP application starts and ends, you'll need a little bit more explanation of how ASP works. For your Application_OnStart subroutine to be called, the first user must request an .asp file from the virtual directory of your ASP application. The user can request an HTML file or another type of file from that directory, but these requests will not cause the Application_OnStart subroutine to be called. The user must explicitly request an ASP file. This is the only time this subroutine will be called, unless you restart the application. Restarting the application usually involves restarting the Web service.

You should use the Application_OnStart subroutine to initialize global variables across the lifetime of the Web application. A good example of a variable to initialize or set in your Application_OnStart subroutine is one that counts the number of users who have used your application. To improve performance, you should initialize the server components you are going to use for each user in the Application_OnStart subroutine. Figure 10-1 shows a Web browser sending a request to an ASP application for the first time.

Figure 10-1: When the first user of an application requests an .asp file, the Application_OnStart event is fired and then the Session_OnStart event fires.

Unlike the Application_OnStart event, the Session_OnStart event is called for any user who makes an application file request. With ASP, each user of your application is considered to have a distinct session with the Web server. As a user browses Web pages in your ASP application, ASP implements and maintains state in a session by using cookies ”whenever a user connects to your application, a file containing information (a cookie) is saved on the user's machine. When the session ends and the user closes his or her Web browser, the cookie is removed and the session is invalidated. If the user reconnects to your application, his machine receives a new cookie and a new session is started. For this reason, users of your application must support and accept cookies; otherwise , your ASP applications will not fully function. You can still use the server-side script of ASP, but you cannot maintain state information for any of your users. With ASP .NET, you can track state without cookies.

The Session_OnStart event is best used to initialize session variables for individual users. Session scope variables might include a connection to Exchange Server for an individual user and personalized information that a user sets in your application ” for example, a user's preference for the background color of Web pages could be stored in a session variable. Each page the user accesses from your site during a session would be displayed with this background color. Figure 10-2 shows each Web browser starting a new session when accessing an ASP application.

Figure 10-2: When a new user accesses your ASP application, the Session_OnStart event fires; Application_OnStart fires only when the first user accesses your application.

The Session_OnEnd event is called when the session with the Web server ends. This end state can be reached in two ways:

By default, IIS sets the timeout interval at 20 minutes. You can change this interval either through the administration program for IIS or by setting the TimeOut property on the intrinsic Session object in ASP. For example, to set a particular script timeout to 10 minutes, you would write the following code in your ASP application:

<% Session.TimeOut = 10 %>

The second way to reach the end state ”by explicitly calling the Abandon method on the Session object ”immediately ends the session and calls the Session_OnEnd event.

One final note about sessions: you have to be careful when you redirect people to other virtual directories in your application. Developers, including me, commonly make the mistake of redirecting users to another virtual root, forgetting that this is considered by ASP to be an application. When you do this, the session variables you establish in one application will not transfer to the other application unless you use the Server.Transfer method discussed later in this chapter. If you want to share session variables between two applications, you should place both applications in the same virtual directory in IIS or use Server.Transfer .

When a Web application ends, the Application_OnEnd event is called. You end a Web application in one of two ways: by shutting down the Web server or by stopping your application by using the Unload button in the IIS administrator. To use the Unload button, you must be running your Web application in a separate memory space. Be sure to save any application scope variables to a persistent medium, such as to your Exchange server or to a database, so that when your application restarts, the Application_OnStart event can reload the values. For example, you don't want a user-counter variable to restart at zero every time your application restarts. In this event handler, you should also destroy any server objects that you have created with an application scope, eliminating potential memory leaks on your server.

Global.asax File

With ASP.NET, you have a global.asax file rather than a global.asa file. While similar events to the ones we discussed earlier are available in ASP.NET, these events have new names , such as Application_Sstart and Session_Start rather than Application_OnStart and Session_OnStart . Also, there are some other events that the global.asa file does not contain but a global.asax can contain. Here is a list of the events that the global.asax file supports:

Event Name

Description

Application_Start

Fires when the first user hits your Web site.

Application_End

Fires when the last user in the site's session times out.

Application_Error

Fires when an unhandled error occurs in the application.

Session_Start

Fires when any new user hits your Web site.

Session_End

Fires when a user's session times out or ends.

Application_AcquireRequestState

Fires when ASP.NET acquires the current state (for example, session state) associated with the current request.

Application_AuthenticateRequest

Fires when a security module establishes the identity of the user.

Application_AuthorizeRequest

Fires when a security module verifies user authorization.

Application_BeginRequest

Fires when ASP.NET starts to process the request, before other per-request events.

Application_Disposed

Fires when ASP.NET completes the chain of execution when responding to a request.

Application_EndRequest

Fires as the last event during the processing of the request, after other pre-request events.

Application_PostRequestHandlerExecute

Fires right after the ASP.NET handler (a page or an XML Web service) finishes execution.

Application_PreRequestHandlerExecute

Fires just before ASP.NET begins executing a handler such as a page or an XML Web service.

Application_PreSendRequestContent

Fires just before ASP.NET sends content to the client.

Application_PreSendRequestHeaders

Fires just before ASP.NET sends HTTP headers to the client.

Application_ReleaseRequestState

Fires after ASP.NET finishes executing all request handlers. This event causes state modules to save the current state data.

Application_ResolveRequestCache

Fires after ASP.NET completes an authorization event to let the caching modules serve requests from the cache, bypassing execution of the handler (the page or Web service, for example).

Application_UpdateRequestCache

Fires after ASP.NET finishes executing a handler in order to let caching modules store responses that will be used to serve subsequent requests from the cache.

Built-In ASP Objects

The real power of ASP applications is that you can write server-side scripts and use their intrinsic objects. ASP and its built-in objects enable you to generate custom responses and maintain state information. We'll look next at the five built-in objects in ASP: Application , Session , Request , Response , and Server .

Application Object

The Application object is used to store global data related to an application that can be shared among all users. By using the methods and properties of this object in your application, you can create and set variables that have an application scope. To be sure that you do not run into concurrency issues when setting your application-level variables, as multiple users can be using the same application simultaneously , the Application object provides two methods: Lock and Unlock . These methods serialize the access to application-level variables so that only one client at a time can read or modify the values. The following example shows how to use the Lock and Unlock methods to increment a user-counter variable whenever a user accesses the application. The Application object maintains these variables in an internal collection. The example also shows how to set and retrieve application-level variables by using the Application("VariableName") syntax:

<HTML> <HEAD> <TITLE>Example: Application Object</TITLE> </HEAD> <BODY> <% Application.Lock Application("NumVisitors") = Application"("NumVisitors") + 1 Application.UnLock %> Welcome! You are visitor #<%=Application"(""NumVisitors")%>. </BODY> </HTML>

The Application object also contains two other collections in addition to the variables collection ” Contents and StaticObjects . These collections allow you to browse through the application-level objects and variables you have created. You probably won't use either of these collections in your final application, but both of them provide great debugging functionality. For example, the Contents collection enables you to list the items that have been added to your application through a script command, and the StaticObjects collection enables you to list the items with an application scope that have been added using the <OBJECT> tag. By adding debugging code to your application at design time, when you run into application object problems, you can make ASP list the objects you've created with an application scope. The following code creates debugging code for the Contents and StaticObjects collections. The code output is shown in Figure 10-3. As you can see, objects and variables both can have an application scope.

Figure 10-3: The debug output for the Contents and StaticObjects collections

<HTML> <HEAD> <TITLE>Debugging Application Objects</TITLE> </HEAD> <BODY> <% 'Create some application variables Application.Lock Set Application("oCDOSession") = _ Server.CreateObject("MAPI.Session") Application("counter") = 10 Application.UnLock %> <P>Objects from the Contents Collection<BR> <% For each tempObj In Application.Contents response.write tempObj & "<BR>" Next %> <P>Objects from the StaticObjects Collection<BR> <% For each tempObj In Application.StaticObjects response.write tempObj & "<BR>" Next %> </BODY> </HTML>

Session Object

The Session object is one you'll use a lot in your Web applications. It holds the variables for individual users across the Web pages in your application. When you place a variable in the Session object, that variable is valid only for the current user and cannot be shared among users in the same way that an application variable can.

Like the Application object, the Session object contains the Contents and StaticObjects collections. You can create session variables in the same way you create application variables, by using the syntax Session("VariableName") .

The properties for the Session object include CodePage , LCID , SessionID , and TimeOut . The CodePage property represents the language code page that will be used to display the content for the HTML page, such as:

<% @LANGUAGE=VBSCRIPT CODEPAGE = 1252 %>

You can use the LCID , or locale identifier, property in conjunction with the CodePage property. The LCID property stores a standard international abbreviation that uniquely identifies a system-defined locale.

The SessionID property returns the unique session identifier for the current user. You should remember, however, that this ID is unique only during the lifetime of the ASP application. If you restart your Web server and therefore restart your Web applications, the Web server might generate the same IDs it already generated for the users before the Web application was restarted. For this reason, you should avoid storing these IDs and attempting to use them to uniquely identify a user of your application. If you always need to uniquely identify your users whenever they access your application, you should use globally unique identifiers (GUIDs) in cookies that are saved on the users' computers. You can also store their information in a SQL Server database and pull that information when they log on to the application.

The fourth property of the Session object is the Timeout property. This property enables you to change the timeout period associated with a particular ASP session. Remember that the timeout is set to 20 minutes by default. If you know that your application will be used for less than 20 minutes, you might want to decrease the duration of the timeout so that sessions end more quickly and resources are returned to the Web server at a faster rate.

The only method of the Session object is the Abandon method. As mentioned earlier, when you call this method, the user's session with the Web server as well as any associated objects and variables for that session are destroyed . If the user attempts to reconnect to the Web application, a new session starts on the server.

Request Object

The Request object allows you to access the information that was passed from the Web browser to your Web application. The Request object is crucial in ASP applications because it enables you to access user input for your server-side scripts. For example, suppose a user fills out an HTML form that you created. Once the user clicks the Submit button on the form, the Request object contains the form information that was passed to the server. By using the collections of the Request object, you can retrieve that information and your application can respond based on the user's input.

Request object collections

The Request object collections are created when the user submits a request to the Web server either by requesting an ASP file or by submitting an HTML form by clicking the Submit button. The three collections of the Request object that you'll primarily work with in your ASP applications are the Form , QueryString , and ServerVariables collections.

Note  

For information on the other two Response object collections, ClientCertificate and Cookies , refer to the IIS documentation.

To understand when to use these collections, you first need to know about the different ways information can be passed from the Web browser to the Web server. Normally in your Web applications, you use HTML forms to gather input from the user so that you can use it in your calculations or store it in a data source. There are two main ways input is passed to the Web server from the client browser: the Get method and the Post method. The example that follows shows an HTML page that contains both methods on the same page.

<HTML> <HEAD> <TITLE>Forms Galore</TITLE> <meta name="GENERATOR" content="Microsoft FrontPage"> </HEAD> <BODY> <form method="GET" action="getinfo.asp" name="GetForm"> <p>What is your e-mail address?</p> <p><input type="text" name="email" size="20"></p> <p><input type="submit" value="Submit" name="GetSubmit"> </p> </form> <form method="POST" action="getinfo.asp" name="PostForm"> <p>What is your first name?</p> <p><input type="text" name="firstname" size="20"></p> <p><input type="submit" value="Submit" name="PostSubmit"> </p> </form> </BODY> </HTML>

The Action attribute for each of the HTML forms specifies the same ASP file, getinfo.asp. The getinfo.asp file is shown here:

<HTML> <HEAD> <TITLE>Post and Get Methods Example</TITLE> </HEAD> </BODY> <%txtRequestMethod = Request.ServerVariables("REQUEST_METHOD")%> You selected to use the <B><%=txtRequestMethod%></B> Method. <P><% if txtRequestMethod="GET" then %> You entered your e-mail address as: <B><%=Request.QueryString("email")%></B> <% else %> You entered your first name as:&nbsp <B><%=Request.Form("firstname")%></B> <% end if %> </BODY> </HTML>

This ASP code uses the ServerVariables collection of the Request object to check whether the form's Request method was a Post or Get method. Once the file determines which method was used, it displays the correct information for that particular type of form. Figure 10-4 shows a sample of the Get method.

Figure 10-4: When a user types an e-mail address and submits the form, the Get method is used to pass the information to the Request object.

Note  

You can also retrieve other server variables, such as HTTP_USER_AGENT , which returns information about which browser the client is using, and LOGON_USER , which represents the Windows account the user is currently logged on to. For a complete list of server variables, see the IIS documentation.

As you can see in Figure 10-4 with the Get method, the information from the form is actually appended to the URL ”for example:

http://exserver/examples/getinfo.asp?email=thomriz@microsoft.com&GetSubmit=Submit

When data is appended to the URL using the Get method of a form, you use the QueryString collection of the Request object to retrieve the data. When using the QueryString collection, follow this format to retrieve the information:

Request.QueryString("VariableName")

Because the information passed to your application appears in the address of the user's browser, the user can see it, so you might want to restrict when you use the Get method. Instead, consider using the Post method.

The Post method places the form information inside the HTTP header, hiding the information from the client. However, when the Post method is used to submit form variables, you cannot use the QueryString collection. Instead, you need to use the Forms collection of the Request object. In the preceding example, the line

Request.Form("firstname")

retrieves the information the user typed into the First Name text box on the form. You can use this same syntax in your applications to retrieve information from an HTML form.

Response Object

The Response object is used to control the content that is returned to the client. For example, when you calculate a value on the server, you need a way to tell the ASP engine that you want to send the information back to the client. You do this by using the Write method of the Response object.

The Write method will be the most commonly used method in your ASP applications. Even though you have not seen any explicit statements using the Response.Write method in the examples, they are there. The syntax <%=Variant%> is equivalent to <% Response.Write Variant %> . The shorthand version makes it easier for you to put these statements in your code.

The Response object has a number of other collections, properties, and methods that you can use, such as the Expires property, which tells the Web browser how long to cache a particular page before it expires. If you do not want your clients to cache your Web pages, you would add the following line to your ASP files to cause your Web page to expire immediately on the user's local machine:

<% Response.Expires = 0 %>

The Response object allows you to buffer the output of your ASP page, which is useful if you want to hold back the output of your ASP code until the script completes its processing. The best example of when to use buffering is to capture errors in your code. For example, by turning on buffering using the command Response.Buffer = True , you can check throughout your ASP code whether an error has occurred. If one has, you can clear the buffer without sending its contents by using the Response.Clear method. You can then replace the output with new output, such as Response.Write "An error has occurred. Please contact the administrator." Finally, you can call the Response.End method, which sends the new contents of the buffer to the client and stops processing any further scripts in the page.

Server Object

The Server object provides you with utility methods and properties with which you can modify the information on your Web server. This object is used extensively in ASP applications because it contains both the CreateObject method and the ScriptTimeout property.

The CreateObject method allows you to create an object on the Web server by passing in the ProgID for the object. Let's look at an example. To create a CDO object, you would type this in your ASP file:

Set oSession = Server.CreateObject("MAPI.Session")

ASP creates an object and passes that object to your oSession variable. By default, when you do this on an ASP page, the object has page-level scope. This means that when ASP is done processing the current page, the object is destroyed. Therefore, you might want to create objects on a page and then store them by assigning them to either session variables or application variables, as shown in this code snippet:

<% Set oSession = Server.CreateObject("MAPI.Session") Set Session("oSession") = oSession %>

As you learned earlier, an object that is assigned either a session or an application scope will be destroyed when either the session or the application ends, respectively. The one issue to watch out for with the CreateObject method and some objects is potential performance loss. You can instantiate almost every object on your Web server as an ASP object, but some objects are specifically designed to run in a server-based, multiuser environment such as CDO. When you instantiate an object that was not designed for an ASP environment, application performance might suffer if too many people hit the page containing that object at the same time.

The ScriptTimeout property of the Server object allows you to specify how long a script should run before it is terminated. By default, an ASP script can run for 90 seconds before it is terminated , but this interval might not be enough time to retrieve data from some data sources. By using the following syntax for this property, you can increase or decrease the amount of time the script will run before termination:

Server.ScriptTimeout = numseconds

Avoid increasing this number much beyond 90 seconds; users who are waiting for long periods of time might assume the page did not load correctly and might click their Stop and Refresh buttons continuously, flooding your Web server with requests.

With the Server.Transfer method, you can specify another ASP file to execute in a different ASP application without losing your existing variables in the calling ASP application. Use this method if you are going to transfer users from one virtual directory to another in IIS. Remember that different virtual directories are usually considered separate applications to IIS. For example, you might have two distinct applications on your IIS machine and you might need to move the user from one application to another but you do not want to lose the state information for the user in the transfer.

Server-Side Include Files

One powerful feature beyond the use of intrinsic objects in ASP is the ability to use server-side include files in your ASP files. Include files are just text files containing script or HTML that you want to add to your ASP page. Outlook Web Access relies heavily on server-side include files for common code libraries in its ASP files. Here are some examples of server-side include files:

<!-- #include file="library/vbsfunctions.inc" --> <!-- #include virtual="/library/vbsfunctions.inc" -->

Using Type Libraries in ASP Applications

ASP uses VBScript, which does not use constants. Therefore, if you want to use globals or constants from a type library, you have to declare the constants yourself or import these constants into your application to use them throughout your code, which ASP allows you to do. The way you do this is by using the METADATA keyword in your applications. The following example shows the use of this keyword in your Global.asa file, which will make the constants available throughout your ASP application.

<!--METADATA TYPE="typelib" UUID="CD000000-8B95-11D1-82DB-00C04FB1625D" NAME="CDO for Exchange 2000 Type Library" --> <!--METADATA TYPE="typelib" UUID="CD001000-8B95-11D1-82DB-00C04FB1625D" NAME="Microsoft CDO Workflow Objects for Microsoft Exchange"--> <!--METADATA TYPE="typelib" UUID="25150F00-5734-11D2-A593-00C04F990D8A" NAME="Microsoft CDO for Exchange Management Library"--> <!--METADATA TYPE="typelib" UUID="00000205-0000-0010-8000-00AA006D2EA4" NAME="ADODB Type Library" -->

Server Components

ASP can take advantage of built-in objects and also use server components to add functionality to your application. An example of two such components are Microsoft ActiveX Data Objects (ADO) and CDO. ADO allows you to connect to many types of databases; CDO allows you to connect to Exchange Server and other messaging servers. You can also write your own components using any COM-based development tool.

WebDAV Support

IIS also supports Web Distributed Authoring and Versioning (WebDAV). WebDAV is a set of extensions to HTTP that allows you to send to your Web server commands that will open , edit, move, search, or delete files. Exchange and SharePoint Portal Server (SPS) support WebDAV, so you'll learn more about it when I discuss Exchange and SPS in later chapters.

Категории