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.


MIND


Inside Knowledge
Aaron Skonnard

Understanding the IIS Architecture
V
isual Basic®has arguably become the most popular language for developing COM components in the middle tier. While most programmers using C++ may have a hard time accepting this, even they cannot deny the fact that Visual Basic 6.0 offers higher levels of productivity than most other languages without sacrificing significant control over standard COM functionality.
      Because most middle-tier development today is Internet-based, Web developers are among the first to benefit from the productivity gains of Visual Basic. Web developers who take advantage of Visual Basic along with the Microsoft®Windows®DNA infrastructure are able to complete their Web-based solutions in record time. This fast pace, however, can often lead to solutions that are less than optimal because developers are taking less time to understand the middle-tier infrastructure.
      Web developers must rely on several pieces of middle-tier infrastructure, including Microsoft Internet Information Services (IIS) and Microsoft Transaction Services (MTS), to create highly scalable Web applications. Although MTS has captured the spotlight in the middle tier, Web developers must understand the IIS architecture and, more importantly, the relationship between IIS and MTS to create optimal solutions. To help foster this understanding, let's walk through the key components of IIS.

IIS Basics

      First and foremost, IIS is a protocol server. It is implemented as a set of several system services that use the most common Internet protocols including HTTP, FTP, Network News Transfer Protocol (NNTP), and the Simple Mail Transfer Protocol (SMTP). As you know, HTTP has become the ubiquitous protocol used in today's Web applications.
      IIS also offers standard APIs for extending and customizing the server's capabilities. These APIs are known as the Common Gateway Interface (CGI) and the Internet Server API (isapi). CGI is almost never used in IIS applications because it requires a new Win32®process for each HTTP request. Win32 process creation and destruction is relatively expensive, so this approach doesn't scale well in high-volume Web sites.
      The isapi model was introduced to step in where CGI failed. isapi is based on the Win32 DLL architecture. Instead of loading a new process for each request, IIS loads an isapi-compliant DLL into its process and calls a well-known entry point to satisfy the HTTP request. Once the isapi DLL is loaded, it remains loaded until the IIS process is torn down. Hence, a single isapi DLL can satisfy all HTTP requests without any operating system overhead.
      The downside to isapi is that it's difficult to implement correctly. If you're developing for isapi you obviously have to use a language capable of creating isapi-compliant DLLs. While this is not directly possible from Visual Basic, creative programmers have developed mapping layers that allow Visual Basic code to participate in the isapi architecture. Nevertheless, most isapi developers stay with languages like C or C++ for better performance (no mapping layer) and more control over thread safety.
      Because Microsoft didn't want to force Web developers to use these complex APIs directly, they introduced Active Server Pages (ASP) as a higher-productivity alternative. ASP is completely based on the isapi architecture. In fact, ASP is implemented as a system isapi DLL (asp.dll, also referred to as the ASP runtime). When a request for an ASP page comes in, IIS makes sure that the ASP runtime is loaded and uses it to process the page.
      ASP pages can contain both HTML and script from any scripting language that supports the ActiveX®scripting interfaces, such as VBScript or JScript®. Any HTML found in an ASP page is simply buffered back to the HTTP response. Script, however, is just-in-time compiled and executed using the appropriate scripting language engine. Because developers using Visual Basic can implement code for the isapi architecture with a familiar language like VBScript, ASP offers the best solution for high productivity and exceptional performance.

Introducing the WAM

      When isapi and ASP were first introduced, they were based on in-process execution. In other words, all isapi DLLs, including the ASP runtime, were always loaded into the IIS process (inetinfo.exe). Since the isapi architecture was based on the Win32 DLL architecture and C-style function calls, it was not possible to isolate isapi code from the Web server process. This turned out to be very frustrating for Web developers since a single faulty isapi DLL was capable of bringing down all Web sites hosted on the server.
      With the release of IIS 4.0, Microsoft introduced a new and improved isapi architecture that promised to increase the fault tolerance of Web applications by allowing isapi code to run in an isolated process from the Web server. Logically, this new architecture is completely COM-based and integrated with MTS.
      The IIS 4.0 architecture is based on a new component called the Web Application Manager (WAM). You can think of the WAM as a simple COM wrapper around existing isapi functionality. The WAM is implemented as a standard MTS-registered COM object that encapsulates all the logic required to locate and load an isapi DLL and process the isapi request. Each IIS application has an associated WAM object responsible for its isapi functionality.

Figure 1: IIS App Isolation
      Figure 1: IIS App Isolations

      Since the WAM is a standard MTS component, it can take advantage of MTS-provided process isolation. Furthermore, because MTS process isolation is a declarative attribute of an MTS package, you can configure the WAM to be part of either a library package (it will run in inetinfo.exe) or as part of a server package (it will run isolated in the MTS-provided surrogate process mtx.exe), as shown in Figure 1. Processing isapi requests across processes is as simple as making standard DCOM remote method calls over Microsoft remote procedure calls.

Configuring IIS Applications

      The Internet Service Manager MMC snap-in is the main administration tool for configuring IIS applications. You create new IIS applications by right-clicking on the appropriate Web site and selecting New | Virtual Directory. If you give the new virtual directory execute permissions (for either ASP files or executables), it becomes an IIS application and will have an associated WAM object (see Figure 2), which by default will be configured to run in the IIS In-Process Applications library package. This means that the new application will always run in the same process as IIS (inetinfo.exe). All nonstatic files contained within the new virtual directory are considered part of the IIS application and will be processed by the corresponding WAM object.

Figure 2: IIS In-Process Applications Library Package
      Figure 2: IIS In-Process Applications Library Package

      Once you've created a new IIS application, you can configure it to run in an isolated process space by right-clicking on the application's virtual directory and selecting Properties. On the Virtual Directory tab, simply check the "Run in separate memory space (isolated process)" checkbox (see Figure 3).
Figure 3: Setting Virtual Directory Properties
      Figure 3: Setting Virtual Directory Properties

Once you make the change and press OK, a new MTS server package will be created specifically for your application, and the WAM object will be moved from the IIS In-Process Applications library package to the newly created server package (see Figure 4).
Figure 4: </b>New Server Package
      Figure 4: New Server Package

      As you toggle the "Run in separate memory space (isolated process)" option, the application WAM object simply moves back and forth between the IIS In-Process Applications library package and an application-specific server package.
      In IIS 4.0 you can choose between running your ASP applications in the Web server process or in a separate, isolated process. In IIS 5.0, which is scheduled to ship with Microsoft Windows 2000, you'll have a third choice, which will allow you to let certain IIS applications share an isolated process from the Web server. This protects your Web server from faulty applications while still allowing your cooperating applications fast access to each other, reducing the number of processes required by the system. This choice, which is called pooled in betas of IIS 5.0, is the default setting for a new IIS application (see Figure 5).
Figure 5: The Pooled Setting in IIS 5.0
      Figure 5: The Pooled Setting in IIS 5.0

The Page Object and Transactions

      When IIS first receives a new HTTP request, it uses another system object, sometimes referred to as the WAM director, to determine which WAM object should receive the request. The WAM director uses the requested URL to determine the correct application mapping before delegating the request to the appropriate WAM object (see Figure 6).

Figure 6: The WAM Director in Action
      Figure 6: The WAM Director in Action

      When the appropriate WAM receives a request for an ASP page, it creates another system object called the Page object to process the page. The Page object is responsible for executing any script within the ASP page. Like the WAM object, the Page object executes within MTS. The Page object can even be transactional, depending on the ASP page-level transaction attribute. To make an ASP page transactional, you simply add the following line to the top of the ASP page:


 <%@ TRANSACTION=required %>
      When the Page object is first created, it will check to see if the page requires a transaction by looking for the transaction attribute. If a transaction is required, the Page object will be created within the scope of a new MTS transaction. Since WAM objects are always transactionless, transactional Page objects will always be the root of their transaction (see Figure 7).
Figure 7: Transactional ASP Pages
      Figure 7: Transactional ASP Pages

      If you know that the Page object will always be the root of the transaction, only two of the transaction support values make sense. Remember that regular MTS components can be marked with one of the transaction support values described in Figure 8.
      Since the Page object will always be the root of the transaction, it will never be able to inherit the transaction of the creator. Hence, in the case of ASP pages, "Requires a transaction" is synonymous with "Requires a new transaction," and "Supports transactions" is synonymous with "Does not support transactions." Nevertheless, you can still specify any of the standard transaction support values in ASP—but only two of them make sense (see Figure 9).
      If you're developing your ASP pages with Visual InterDev®6.0, you'll notice that the property sheet for the ASP page only offers two values for the transaction attribute: required and not_supported. Apparently, Visual InterDev doesn't want to take the chance of confusing the user and only offers the two settings that make sense under IIS 4.0.
      With the release of IIS 5.0, the ASP Server object will contain a new Execute method that allows you to directly call one ASP page from another ASP page. So an ASP page called through Server.Execute will no longer necessarily be the root object of the transaction. The following code illustrates a scenario where one ASP page could inherit the transaction of another ASP page through Server.Execute:


 ASP-Page1.asp:
 <%@ TRANSACTION=required %>
 <%
     Server.Execute("ASP-Page2.asp")
     ' more asp code here
 %>

 ASP-Page2.asp:
 <%@ TRANSACTION=required %>
 <%
     ' more asp code here
 %>
      The Page object is responsible for creating any other custom COM objects embedded within the ASP page through the <OBJECT> tag or through calls to Server.CreateObject. Whether these custom COM objects live within the same process as the WAM and Page objects depends upon how the custom COM objects are deployed in MTS.

Putting it All Together

      If you deploy your custom COM objects within the same package as the WAM, they will always execute within the same process as the WAM. However, if you deploy your custom COM objects in their own MTS server package, the Page object will encounter a process context switch every time it interacts with one of your components. Also, don't forget that depending on how you configure your IIS application, it may also be running in a process that's isolated from the Web server. It's easy for developers to unknowingly create configurations that waste CPU cycles on unnecessary cross-process context switches.
      This is not to say that you would never want to isolate certain parts of your IIS application into separate processes. In many situations it's justifiable to trade performance and overall throughput for more fault tolerance and overall robustness. Nevertheless, as a general rule of thumb keep your custom COM objects as close to the WAM as possible for better performance.

IIS Debugging Tip

      When you're developing your IIS application and the COM components you'll be using within your ASP pages, it makes sense to configure your app to run in an isolated process. Before Visual InterDev can launch a debug session for your IIS application, it has to convert the application from an in-process application to an out-of-process application. Hence, manually configuring your IIS application to run in an isolated process will speed up your debug cycle tremendously.

Figure 10: Selecting the Unload Button
      Figure 10: Selecting the Unload Button

      Furthermore, as you're developing custom COM components to use in ASP, you'll also want to have your application configured to run in an isolated process so you can shut down the process on demand. If you right-click on your application virtual directory and select Properties, you should see an Unload button on the Virtual Directory tab (see Figure 10). Pressing this button will shut down the application process (mtx.exe), freeing up any COM objects that may still be loaded in memory, allowing you to recompile at will.
      Understanding the IIS architecture and its tight relationship with MTS should help you understand the issues involved in configuring and deploying your custom COM components in IIS. Once you grasp how the WAM and Page objects behave, you can use your understanding of COM and MTS to create the most optimized solution for your project requirements. Look at some of Ted Pattison's Advanced Basics columns in MIND for more complete coverage of COM and MTS programming models. The following key points summarize what you should understand about the IIS architecture:
  • An IIS application is defined as the contents of a virtual directory with execute permissions.
  • There is a one-to-one mapping between IIS applications and WAM objects.
  • IIS applications can be configured to run in the Web server process (inetinfo.exe) for better performance or in an MTS-hosted process (mtx.exe) to increase robustness.
  • The WAM uses the Page object to process ASP pages.
  • Both the WAM and Page objects are hosted in MTS.
  • The WAM object doesn't support transactions, but the Page object might, depending on the ASP page-level transaction attribute.
  • Generally, you should keep your custom COM objects as close to your WAM as possible for better performance.
  • Both the WAM and Page objects obey the rules of COM and MTS.
  • COM is what makes all of this possible! Without COM you would still be writing in-process isapi DLLs.

From the October 1999 issue of Microsoft Internet Developer.