The IISASP Architecture

[Previous] [Next]

IIS is more than a simple Web server. It's a sophisticated server based on many popular protocols and Internet standards. In addition to HTTP, IIS handles protocols such as File Transfer Protocol (FTP), Network News Transfer Protocol (NNTP), and Simple Mail Transfer Protocol (SMTP). In this chapter, we'll focus on how IIS handles HTTP traffic. In particular, we'll examine how IIS plays the role of Web server for the Windows platform. The information in this chapter is based on IIS 5, which ships with Windows 2000 Server and Windows 2000 Professional.

The initial release of IIS was simply a service that served up static HTML pages. Recent versions of IIS are far more sophisticated. In addition to serving up static Web pages, IIS can run extensive server-side processing in response to HTTP requests.

You can take a few different approaches to server-side processing with IIS. Like many UNIX-based Web servers, IIS can run applications that are based on Common Gateway Interface (CGI). This CGI support makes it relatively easy to port existing Web applications to the Windows platform. However, CGI isn't the best approach when you build an application for IIS. Web development based on the native API for IIS is more flexible and offers much better performance. The native API for IIS is known as the Internet Server API (ISAPI).

Software written directly against ISAPI comes in two flavors: ISAPI extensions and ISAPI filters. ISAPI extensions are invoked in response to HTTP requests for a specific filename extension. ISAPI filters are invoked in response to all HTTP traffic for a specific IIS computer, site, or application.

Writing software directly against ISAPI provides the best performance and greatest flexibility, but it has several daunting requirements. ISAPI software must be compiled into DLLs that expose call-level functions as well-known entry points. Visual Basic doesn't support this, so most ISAPI development is done using C or C++. ISAPI programming also forces you to deal with low-level plumbing details such as implementing a thread-pooling manager and writing custom synchronization code. Most companies avoid creating ISAPI-based software because they don't have the expertise and they're not willing to invest the time and money to get it.

ASP is a popular alternative to ISAPI-based development. ASP doesn't eliminate the need for ISAPI, however. ASP is a runtime layer built on top of ISAPI that hides the low-level grunge of direct ISAPI programming. ASP is itself an ISAPI extension that allows you to write server-side logic using simple scripting languages. The ASP framework provides the convenience of a built-in thread-pooling scheme and eliminates the need to write custom synchronization code.

Since this book focuses on writing software with Visual Basic, I'll leave the topic of writing ISAPI filters and ISAPI extensions for another book. Here, I'll concentrate on what you can do using ASP pages and Visual Basic components.

The ASP Framework

Let's take a moment to review the fundamental concepts of ASP. The ASP framework is built around three important assumptions. First, since Web applications tend to generate pages from static data as well as dynamic data, an ASP page is usually a combination of HTML text (static data) and server-side script (code for generating dynamic data). Second, since developers want to build sites using component-based software, an ASP page can load and run objects from standard COM components. Third, since Web developers need help with state management because HTTP is largely a connectionless protocol, the ASP framework provides a scheme for managing client-specific state as well as application-wide state across HTTP requests.

As you know, an ASP page is a text file that contains HTML and server-side scripts. Server-side scripts can be written in a number of scripting languages, including VBScript and JScript (Microsoft's JavaScript implementation). The ASP runtime handles a request for an .ASP file by running a filter that looks for special tags that enclose instructions to be parsed and executed on the server. The ASP runtime executes these server-side scripts and returns an HTML stream back to the client. This HTML stream can include a combination of static HTML from the page and HTML that is generated dynamically as a result of server-side processing. An ASP developer can write server-side scripts to run business logic, access databases, and interact with COM objects.

In addition to providing an easy way to run scripts and Visual Basic objects on the Web server, the ASP runtime also provides support for state management. The ASP designers recognized the difficulty of managing application-wide variables and client-specific state when you develop applications based on a connectionless protocol such as HTTP. The ASP framework exposes a name/value dictionary called the Application object for sharing in-memory data across all the clients of a specific application. The ASP framework solves the more difficult problem of managing client-specific state through another name/value dictionary called the Session object.

The session-management facilities of the ASP framework are made possible by the passing of HTTP cookies between the IIS Web server process and the client's browser. The generation and management of these cookies as well as the caching of client-specific state is transparent to the ASP developer. Anyone who's programmed against the ASP Session object can tell you how easy it is. The ASP runtime does almost all the work behind the scenes.

ASP application variables and ASP session variables are accessible to ASP developers as well as to Visual Basic developers who are creating components for IIS. These ASP state management features make it much easier for you to build session-based applications in which clients build up server-side state over a series of ASP requests. However, you must understand how the use of ASP session-management can limit an application's scalability. Over the course of this chapter, I'll tell you several reasons why ASP session variables are inappropriate for large-scale applications.

IIS Applications

The main Web server process for IIS runs as a Windows service and is launched from an executable named INETINFO.EXE. All incoming HTTP requests are initially sent to this Web server process. If IIS sees that a request is for a static Web page (such as a file with an .HTM extension), it simply returns the page to the client. However, if IIS determines that the request should be routed to an IIS extension such as the ASP runtime, it calls upon a system-provided helper object known as the Web Application Manager (WAM).

If you look at the COM+ Applications folder of a Windows 2000 server (with IIS installed), you'll see a library application named IIS In-Process Applications. This application contains a free-threaded component named IISWAM.W3SVC that's installed along with IIS. This component is a WAM that routes incoming requests for ISAPI extensions to the proper DLL. For example, when a WAM receives a request with an .ASP extension, it redirects the request to ASP.DLL.

IIS uses an abstraction known as an IIS application to map URLs to physical directories. For this reason, an IIS application is also known as a virtual directory. The installation of IIS automatically creates a default Web site that serves as the root application. The path to the site's home directory is typically something like C:\InetPub\wwwroot. You can configure additional IIS applications by creating virtual directories using the IIS administrative tool called the Internet Services Manager. For instance, you can map a URL such as http://LocalHost/MyApplication to a physical directory of your choice. Once you create a virtual directory, you can simply add your HTML and ASP pages to the appropriate directory and everything from that point down in the directory hierarchy is part of the IIS Application (until you reach another IIS Application).

As you can see, it's pretty simple to get an IIS application up and running. If you're not familiar with setting up and managing IIS applications, you should read through the documentation that ships with IIS 5. The documentation for IIS is itself a virtual directory that's accessible through the path http://LocalHost/iishelp. It offers step-by-step instructions for creating and managing IIS applications.

IIS tracks configuration information for IIS-specific entities such as computers, sites, and applications in a special database called the IIS metabase. The IIS metabase is similar in concept to the COM+ registration database (RegDB) and the Windows Registry, but it is a separate data store used exclusively by IIS.

The IIS metabase is a hierarchical database file that holds key/value pairs. Some metabase keys are configurable through the Internet Services Manager. Other important metabase keys are accessible only programmatically through IIS Admin Objects, which are accessible through Active Directory Services Interfaces (ADSI).

Later in this chapter, I'll show a brief example that uses IIS Admin Objects with ADSI. You'll find a complete overview of writing administrative scripts and programs in the IIS documentation or the Platform SDK by searching on "Administering IIS Programmatically." These resources offer more information on accessing the metabase keys with Windows Script Host (WSH) files or with Visual Basic.

Processing an ASP Request

Figure 9-1 shows the flow of a typical ASP request. The request is initially handled by a WAM object, which routes it to the ASP runtime. The ASP runtime responds by creating an internal page object. The page object runs a filter on the requested ASP page to parse out any server-side processing instructions. Note that the programmatic interfaces exposed by WAM objects and by internal page objects are undocumented. You never have to interact with them directly. However, once you see how these system objects interact with one another, you'll have a much better understanding of how an ASP request is processed.

click to view at full size.

Figure 9-1 WAM objects route requests for .ASP files to the ASP runtime, which responds by creating an internal page object to filter out and run server-side scripts.

The WAM is a free-threaded object. When it calls into an ISAPI extension such as ASP.DLL, it uses a multithreaded apartment (MTA) thread that's been dispatched from a thread pool maintained by the IIS runtime. One of the trickier aspects of creating an ISAPI extension is dealing with concurrency and synchronization issues caused by this MTA thread pool. The ASP runtime makes things easier by switching each ASP request over to a single-threaded apartment (STA) thread before running the code in an ASP page. The ASP runtime manages a separate pool of STA worker threads. (Behind the scenes, ASP is actually using COM+ thread pooling to accomplish this.) The ASP designers created this thread-pooling scheme to provide an optimized balance between concurrency and resource usage while eliminating the need for programmer-assisted synchronization.

Figure 9-2 shows how the ASP runtime switches each request from an MTA thread to an STA thread. A dispatching mechanism in the ASP runtime places each request in a central request queue. STA threads in an ASP-managed pool monitor this queue and service requests on a first-in, first-out basis. Note that the size of this thread pool is dynamic. The ASP runtime spawns additional threads during high-traffic times and releases threads when things quiet down.

click to view at full size.

Figure 9-2 ASP requests are placed in a central request queue, where they're serviced on a first-in, first-out basis by a pool of STA worker threads.

Switching over to an STA thread effectively eliminates concurrency issues, but it also has a noticeable effect on performance. An ISAPI extension DLL that processes each request on a single MTA thread provides faster response times. You can easily see the difference in performance by benchmarking ISAPI extension DLLs against ASP requests. However, most companies are willing to give up a degree of performance in return for an environment in which it's far easier to write software. They assume that additional hardware can compensate for the overhead of the ASP threading scheme.

Note that IIS 5 provides an optimization that wasn't offered in earlier IIS versions. When the ASP request dispatcher encounters an ASP page that doesn't include any server-side processing tags, it simply processes the page on the MTA thread without sending it to the request queue. This improves performance noticeably. In earlier versions of IIS, you had to use pages with an .HTM or .HTML extension in order to avoid the overhead of a thread switch. Now all pages can have an .ASP extension regardless of whether they have server-side processing tags. The thread switch is incurred only when needed.

IIS provides a way to configure the maximum size of the STA thread pool and the maximum size of the request queue. The thread pool size is controlled by the AspProcessorThreadMax key in the IIS metabase. The default setting for this key is 25 per processor per process. On a quad-processor machine, that means that each process that hosts ASP can have up to 100 worker threads. For most production ASP applications, this default setting shouldn't be adjusted. I recommend that you avoid adjusting this key unless you've thought through all issues related to tuning a thread pool. It's easy to inadvertently degrade the responsiveness and throughput of your site by setting this value too high.

The primary reason to increase the value of AspProcessorThreadMax is to optimize an application in which ASP pages make long-running calls to COM objects running in other processes and on other machines. In most other scenarios, increasing the value of AspProcessorThreadMax hurts performance because of the additional overhead of switching more threads in and out of the Web server's processors. Note that you can't adjust this setting using the Internet Services Manager. You must change it programmatically using an administrative script or a Visual Basic application.

In some situations, the ASP request queue size can also require tuning. If the Web server gets more requests per second than it can handle, the request queue will grow larger and larger. When the queue grows too large, the response times for servicing incoming requests will decrease dramatically. IIS sets a maximum capacity for the queue so that the request backlog doesn't grow too large.

By default, the ASP runtime allows the queue to grow to 3000 requests. Once the queue has reached capacity, additional incoming ASP requests are rejected with a "Server Too Busy" error. This behavior is reasonable because it allows IIS to reject any request that it can't handle in a timely manner.

Adjusting the queue size allows you to change the point at which the Web server starts rejecting incoming requests. You must strike a balance between high availability and shorter response times. The whole point is to configure the queue size to handle short-term peaks but limit the queue's backlog during extreme workloads. If your Web server gets overloaded, it's better to send error messages back to your clients than to make them wait an unacceptably long time.

You can adjust the AspRequestQueueMax key as well as the AspProcessorThreadMax key programmatically using IIS Admin Objects and ADSI. For example, in a Standard EXE project you can reference the Active DS Type Library and write the following code:

 Dim MyWebServer As ActiveDs.IADs Set MyWebServer = GetObject("IIS://LocalHost/W3SVC") MyWebServer.Put "AspProcessorThreadMax", 30 MyWebServer.Put "AspRequestQueueMax", 1500 MyWebServer.SetInfo 

Let's review by summarizing how the ASP thread pool works for a default installation of IIS on a machine with a single processor. The pool has 25 STA worker threads available per process. (If you want more threads, you should acquire a dual- or quad-processor Web server machine.) When a request arrives, it's placed in the request queue. The ASP runtime dispatches an idle STA thread from the pool, if one is available. (Note that this scheme allows any thread in the pool to process the request.) If all the STA worker threads are busy processing other requests, incoming requests are queued up and processed on a first-in, first-out basis. As long as the queue doesn't reach its default capacity of 3000 requests, all requests are processed.

Now that you understand the threading scheme built into the ASP runtime, let's talk about how to make the most of it as a Visual Basic programmer.

Creating Visual Basic Objects from ASP Pages

Let's begin this section by examining the relationship between a Visual Basic object and the ASP runtime environment. Since you'll be creating and configuring Visual Basic DLLs to run on the Web server, you should understand how object activation and lifecycle management work when you create COM objects from an ASP page. Fortunately, ASP makes it relatively easy to create Web-based applications that leverage Visual Basic components running on the Web server.

The following ASP page uses a server-side script written in VBScript to create a Visual Basic object and interact with it:

 <%@ LANGUAGE="VBSCRIPT"%> <HTML><BODY> <H2>Customer List</H2> <% Dim sProgID, CustomerManager sProgID = "MyWebDll.CCustomerManager" Set CustomerManager = Server.CreateObject(sProgID) Response.Write CustomerManager.GetCustomerListHTML() %> </BODY></HTML> 

You can see how easy it is to create and use a Visual Basic object from an ASP page. Note that the ASP page filter recognizes the inline tags <% and %> as the beginning and the end of a server-side script. Alternatively, you can write server-side scripts in an ASP page using the SCRIPT tag with the RunAt=Server attribute.

I must emphasize that running Visual Basic components from server-side scripts doesn't prevent you from building cross-platform solutions. You can run as much COM code as you'd like on the Web server without creating any client-side dependencies on Microsoft Internet Explorer or the Windows platform. As long as you write platform-independent HTML, the client computers can run a wide range of browser and operating systems. It's up to you to know which HTML tags and client-side scripting techniques create browser-specific dependencies.

Replacing ASP scripts with Visual Basic components

You can reap quite a few benefits by moving business logic and data access code out of ASP pages and into Visual Basic DLLs. ASP pages are great for programming in the small, but managing an application that contains thousands of lines of code can be difficult. Here are a few things to keep in mind when you're deciding whether to place your logic in an ASP page or a Visual Basic component:

  • You get higher levels of encapsulation and code reuse by using a programming language that is class-based and object-oriented, such as Visual Basic.
  • The Visual Basic IDE offers compile-time type checking and the most effective use of IntelliSense. This results in greater productivity and fewer hours spent debugging (especially if you're programming against a COM-based library such as ADO).
  • Visual Basic code is compiled; ASP scripts aren't. This means that logic in a Visual Basic DLL can run faster than a server-side ASP script. However, you can't always assume that moving logic from an ASP page into a Visual Basic component will speed things up. Creating and tearing down Visual Basic objects requires its own share of processing cycles. Moving code out of an ASP page and into a Visual Basic component can actually degrade performance for a request with minimal logic. But as the amount of code for a request increases, the compiled format of Visual Basic code will outperform the equivalent logic in an ASP page.
  • Visual Basic code uses direct vTable binding when you program against COM libraries such as ADO. ASP scripts use IDispatch and late binding on every method call when they interact with a COM object. For example, if a request requires 20 or more calls against ADO objects, the performance penalty for late binding can be significant.
  • COM-based DLLs created with Visual Basic can take full advantage of the integration between IIS and the COM+ runtime environment.
  • You can access the Win32 API directly from an ActiveX DLL but not from a script in an ASP page. (Of course, your Visual Basic code can potentially crash the Web server process if you call a Win32 API function incorrectly.)

You should also keep in mind the issues relating to scripting clients that we discussed in Chapter 4. You have to deal with a few oddities when you write ASP code with a scripting language such as VBScript. First, variables in a server-side script can't be explicitly typed. They are implicitly cast as Variants. This can take some getting used to if you're a Visual Basic programmer.

Second, VBScript can retrieve method output parameters only when they're declared as Variants. If you try to call a method on a Visual Basic object that has an output parameter declared as a String or Double, the VBScript code will fail and generate a "Type mismatch" error. You should therefore design your Visual Basic methods so that output parameters (ByRef) are Variants if you intend to call them from ASP scripts.

You can propagate errors from a Visual Basic object back to an ASP page, but error handling isn't as graceful in VBScript as it is in Visual Basic. Error handling is typically conducted by using an On Error Resume Next statement and checking the error number after each call. This is cumbersome, but it works. Here's an example of handling an error with VBScript in an ASP page:

 <% On Error Resume Next Dim sProgID, CustomerManager sProgID = "MyWebDll.CCustomerManager" Set CustomerManager = Server.CreateObject(sProgID) Response.Write CustomerManager.GetCustomerListHTML() ' Test to see if call experienced a runtime error. If Err.Number <> 0 Then Response.Write "<b>There has been a system error</b><br>" Response.Write Err.Description End If %> 

Lifecycle requirements for apartment-threaded objects

As you know, you can use Visual Basic to create apartment-threaded components that run in the STA model. If you want to create a component that supports a more sophisticated threading model, you must use a different language, such as C++. The good news for Visual Basic programmers is that this doesn't impose much of a limitation in an IIS application because the ASP thread pool is based on STA threads. An ASP page and the Visual Basic objects it creates often run on the same thread. As a result, you can avoid the overhead of COM's proxy/stub layer.

When you create an ActiveX DLL for an IIS application, be sure to leave your project's threading model set to the default setting of Apartment Threaded. Don't change it to Single Threaded, which forces your objects to run in the main STA of the IIS Web server process and causes your objects to load on a different STA thread than the ASP page that created them. This setting degrades performance because it creates an unnecessary proxy/stub layer. Moreover, single-threaded DLLs are undesirable because they can result in strange blocking problems.

It's important to remember that Visual Basic objects exhibit thread affinity. This means that a Visual Basic object can be accessed only by the thread that created it. This isn't a problem when you create and release an object within the scope of a single HTTP request. But if you attempt to hold onto a Visual Basic object across multiple requests by assigning it to an ASP Session variable, you end up pinning the client to a specific worker thread in the ASP thread pool.

To illustrate why this situation is undesirable, let's look at an example that highlights the issues that the ASP designers had to think through when creating their framework. Imagine a request from a client that creates an object and assigns it to an ASP Session variable. The object is created on one of the STA threads from the ASP thread pool—let's say thread 17. What if the next request from the same client is processed by thread 8? A problem occurs because thread 8 can't access an apartment-threaded object created on thread 17. The request would have to switch from thread 8 to thread 17 in order to access the object.

The ASP designers had to choose between two evils. They decided that pinning clients to threads was preferable to having a situation in which a single request requires access to multiple threads from an ASP-managed pool. They added code to the ASP runtime to determine when an apartment-threaded object is assigned to an ASP Session variable. Once a client session is assigned an apartment-threaded object, the ASP runtime routes every request through the same STA worker thread for the duration of the session. This is unfortunate because the ASP thread-pooling scheme works best when it can use the first available thread in the pool.

The ASP thread-pooling model dispatches any thread in the pool to service an incoming ASP request. However, when you assign a Visual Basic object to an ASP Session variable, ASP must locate (and possibly block on) the one thread that created the object. While the ASP runtime can serialize all future requests over the same thread, this situation doesn't allow an application to reach its potential in terms of performance and concurrency. One client can block on another's request even when several STA worker threads are sitting idle in the pool.

The important point to take away from all this is that Visual Basic objects should be used only at page scope. You should never attempt to hold onto a Visual Basic object (or any other apartment-threaded object) with an ASP Session variable because your application won't scale properly. Of course, you might be able to get away with doing this if your site doesn't get much traffic. But you should at least realize the implications of what you're doing.

You've seen the problems associated with apartment-threaded objects and ASP Session variables. Assigning a Visual Basic object to an ASP Application variable creates an even more severe problem. If you assign an apartment-threaded object to an ASP Application variable, the requests from many different clients must be routed through a single thread. (There's actually a special STA thread created for this purpose, so there's always a thread switch and a single point of contention.) This results in severe and unacceptable blocking behavior. If you release your Visual Basic objects at the end of every request, you can avoid this undesirable result.

Partitioning a Web Application into Separate Processes

IIS gives you the option of running your ASP pages in the Web server process (INETINFO.EXE) or in an isolated process. The default Web site and other IIS applications have a configurable Application Protection setting for controlling whether they run in INETINFO.EXE or in a separate, isolated process. Figure 9-3 shows how to adjust the Application Protection setting for an IIS application using the Internet Services Manager.

click to view at full size.

Figure 9-3 You can configure an IIS application to run in INETINFO.EXE or in an isolated process.

To achieve the highest levels of performance, you should run your ASP pages and Visual Basic objects in INETINFO.EXE, as shown in Figure 9-4. You can run your ASP pages in INETINFO.EXE by adjusting the Application Protection setting of the home directory or an IIS application to a value of Low (IIS Process). Note that this isn't the default setting for either the home directory or an IIS application in IIS 5.

If you want to run Visual Basic objects in INETINFO.EXE along with your ASP pages, you can add your components to a COM+ library application. You can achieve the same effect by registering your DLLs with REGSVR32.EXE and running them as nonconfigured components. Objects created from nonconfigured components are slightly faster than objects created from configured components because they don't require system-provided proxies with interception code. However, you should remember that nonconfigured components can't carry declarative attributes or interact with the COM+ runtime.

click to view at full size.

Figure 9-4 Running your ASP pages and Visual Basic objects in INETINFO.EXE provides the best performance.

Although running all your code in INETINFO.EXE provides the best performance, other factors might lead you to run your Visual Basic objects and your ASP pages in a separate process. Perhaps you're more interested in higher levels of fault tolerance. Or perhaps you want to run your Visual Basic components on a separate computer to share a set of business objects across multiple Web servers or to create a more secure environment. When you split an application into multiple processes, you typically give up some degree of performance in order to get something else in return.

The two primary reasons why companies avoid running Visual Basic code in INETINFO.EXE have to do with fault tolerance and upgrading application code. Fault tolerance is an issue because the code in a Visual Basic DLL can potentially crash INETINFO.EXE. For example, if you write a call to a Win32 API function that doesn't handle pointers correctly, you can bring down an entire Web site. Any Visual Basic DLL that contains Declare statements and API calls must be thoroughly tested before being released into production.

You should note that many developers and administrators overestimate Visual Basic's ability to crash INETINFO.EXE. If an ActiveX DLL fails to catch a standard runtime error, the error is simply passed back to the ASP page that created the object. If the ASP page doesn't catch the error, the ASP runtime simply reports the error back to the browser. While unhandled errors don't make for an elegant application, most Visual Basic code can run safely in INETINFO.EXE without the risk of a crash.

The second reason to avoid running Visual Basic code in INETINFO.EXE has to do with upgrading application code. Once a Visual Basic DLL has been loaded into INETINFO.EXE, the Web server process must be shut down before the DLL can be rebuilt or replaced. Some companies find the requirement to shut down INETINFO.EXE unacceptable for a production server. Later in this chapter, we'll look at a few options that allow you to replace a Visual Basic DLL in production without shutting down the Web server process. During development, you'll also want to avoid loading your DLLs into INETINFO.EXE because doing so makes it painful to recompile and test your code.

You can run your Visual Basic code in a separate process in several ways. The first approach we'll look at is configuring your Visual Basic components in a COM+ server application, as shown in Figure 9-5. Your Visual Basic objects are created in an instance of the COM+ container application DLLHOST.EXE. Each call from an ASP page to an object is executed across process boundaries with the help of a proxy/stub pair.

click to view at full size.

Figure 9-5 When an ASP page creates an object from a component configured in a COM+ server application, the ASP page and the object are connected through a proxy/stub pair.

During development, this approach makes it much easier to rebuild a DLL. After you test your DLL, you can simply shut down the COM+ server application and rebuild it. Moreover, you can switch back and forth between running objects in DLLHOST.EXE and in the Visual Basic debugger. If you set up your components for MTS/COM+-style debugging (as described in Chapter 6), you can single-step through code for a Visual Basic object that's been instantiated from an ASP page running in INETINFO.EXE. If you'll be debugging Visual Basic objects created from ASP pages, you should read the following sidebar.

Debugging Visual Basic Components Created from ASP Pages

Visual Basic developers can encounter a problem when they first attempt to debug Visual Basic objects created from ASP pages under Windows 2000. When an ASP page attempts to create an object in the Visual Basic debugger, the ASP runtime reports the error message "The call to Server.CreateObject failed while checking permissions. Access is denied to this object." I'll cover security in greater depth in Chapter 11, but I want discuss this problem here so that you don't get hung up when you start debugging Visual Basic components targeted for an IIS application.

An IIS application has a default security setting that allows anonymous access. When an unauthenticated client submits an ASP request, the ASP page runs as an anonymous user under the IUSR_MachineName account. The process associated with the Visual Basic debugger (VB6.EXE) uses default access permissions that are configured on a machine-wide basis. The IUSR_MachineName account can't call into VB6.EXE until it has been added to the machine-wide default access permissions. You modify the security permissions using a utility called DCOMCNFG.EXE. If you run DCOMCNFG.EXE from the command line, you can change the machine-wide Default Access Permission setting on the Default Security tab. DCOMCNFG.EXE provides a standard Windows access control list (ACL) editor that lets you grant access permissions to IUSR_MachineName or any other user account. Keep in mind that this opens up a potential security hole that's probably far more acceptable for a development workstation than it is for a production server.

Another quick way to get around this security problem is to disable anonymous access for the default Web site using the Internet Service Manager and rely on Integrated Windows authentication during debugging. If you do this, ASP pages don't run as IUSER_MachineName. Instead, they run under the interactive user account—the same user account that the browser runs under. If you're doing all your debugging on a single machine, the Visual Basic debugger also runs under the interactive user account. Therefore, COM security checks allow ASP pages to create and interact with objects in VB6.EXE.

Note that the problem I've described in this sidebar is an issue only when you debug an ActiveX DLL in the Visual Basic IDE. The problem doesn't affect Visual Basic objects running in a COM+ application.

Another good reason to add your components to a COM+ server application is to run objects on a separate computer that serves as a dedicated application server. You might want to do this, for example, if you want to have a single application server that's used by many different Web servers. Or you might want to balance the processing load of the application across several computers or have your business objects run on a computer that's more secure than the Web server. Once you install your Visual Basic components in a COM+ server application on the application server computer, it's pretty easy to create an application proxy and install it on any Web server that needs to access it. ASP pages can then create objects from across the network.

As you know, out-of-process calls are expensive. Calls that cross computer boundaries are even more expensive. If ASP pages will be calling objects that live in other processes, you must design your components to minimize the number of round trips. This is an important aspect of distributed application design.

Isolated IIS Applications

You've learned one way to run your Visual Basic objects in a separate process outside of INETINFO.EXE. IIS also lets you run your ASP pages outside of INETINFO.EXE. If you set the Application Protection setting for an IIS application to Medium (Pooled) or High (Isolated), your ASP pages will run in an instance of the COM+ container application DLLHOST.EXE.

Figure 9-6 shows how things work when you set an IIS application's Application Protection setting to High (Isolated). IIS has to perform a little trickery to run ASP pages in an isolated process. When you change the setting of an IIS application to High (Isolated), IIS creates a new COM+ server application with a special WAM component. You can actually verify this by refreshing and examining the COM+ Applications folder in the Component Services administrative tool after you make the adjustment.

When IIS receives the first request for the isolated IIS application, the W3SVC WAM object in INETINFO.EXE creates an instance of this special WAM component, which forces the COM+ runtime to launch a new instance of DLLHOST.EXE. From that point on, all requests for this isolated IIS application are routed across these two WAM objects. The result is that all ASP pages associated with the isolated IIS application run in their own private process.

click to view at full size.

Figure 9-6 When an IIS application has an Application Protection setting of High (Isolated), it runs in a private instance of DLLHOST.EXE.

Keep in mind that there is a performance penalty for every request because it requires an out-of-process COM call from one WAM object to another. However, unlike the deployment scheme depicted in Figure 9-5, calls from ASP pages into a Visual Basic object don't have to go across process boundaries. As long as your components are in a library application or are registered as nonconfigured components, your objects are created in the same process and on the same thread as the ASP page that created them. Such a model gives acceptable performance even when an ASP page makes multiple calls into an object.

The final deployment scheme is simply a minor variation of the one you just saw. When an IIS application runs with Medium (Pooled) protection, it runs in a shared instance of DLLHOST.EXE along with any other IIS application that has the same setting. Note that Medium (Pooled) is the default Application Protection setting for the home directory as well as every new IIS application. Figure 9-7 shows how requests are routed to their proper destinations.

One motivation for running IIS applications in isolation has to do with security. INETINFO.EXE runs as a Windows service under the identity of the system. Isolated IIS applications, on the other hand, run under the identity of a more restricted user account. This means that isolating an IIS application can lower the risk of attacks on your Web site. I'll revisit this topic in Chapter 11 when I talk about IIS security.

You've now seen quite a few possible deployment scenarios. You can run all your ASP pages and Visual Basic objects in INETINFO.EXE. You can run your ASP pages in INETINFO.EXE and run your Visual Basic objects in a COM+ server application. You can run your ASP pages and objects outside of INETINFO.EXE. In fact, you can partition a Web application in just about any way that makes sense.

click to view at full size.

Figure 9-7 Every IIS application with an Application Protection setting of Medium (Pooled) runs in a shared instance of DLLHOST.EXE.

What's really neat about these deployment options is that they don't necessarily affect the way you write your ASP pages or your Visual Basic components. (The one exception is when you've created a Visual Basic component that has an in-process dependency for performance reasons.) When you finish writing your application, you can change from one deployment option to another without rewriting any code. You can simply change the Application Protection setting of an IIS application or the activation setting of a COM+ application.

For example, you can test and debug your code in the development environment by running your Visual Basic components in a COM+ server application. This makes it much easier to unload and recompile your DLLs. When it's time to put your code into production, you can configure your site to run your ASP pages and your Visual Basic objects in INETINFO.EXE to achieve the best possible performance.



Programming Distributed Applications with COM+ and Microsoft Visual Basic 6.0
Programming Distributed Applications with Com and Microsoft Visual Basic 6.0 (Programming/Visual Basic)
ISBN: 1572319615
EAN: 2147483647
Year: 2000
Pages: 70
Authors: Ted Pattison

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