This article is an excerpt from Inside Microsoft Windows SharePoint Services 3.0 by Ted Pattison and Daniel Larson, from Microsoft Press (ISBN 9780735623200, copyright 2007 by Microsoft Press, all rights reserved). No part of these chapters may be reproduced, stored in a retrieval system, or transmitted in any form or by any means—electronic, electrostatic, mechanical, photocopying, recording, or otherwise—without the prior written permission of the publisher, except in the case of brief quotations embodied in critical articles or reviews.
- Review important concepts and terms for IIS and ASP.NET.
- Understand how Windows SharePoint Services extends the ASP.NET routing infrastructure.
- Understand the difference between site pages and application pages.
- Learn to create custom application pages.
- IIS and ASP.NET 2.0 Primer
- ASP.NET 2.0 Framework
- Windows SharePoint Services Integration with ASP.NET
IIS and ASP.NET 2.0 Primer
This chapter examines the core architectural details of how Windows SharePoint Services integrates with Internet Information Services (IIS) 6.0 and Microsoft ASP.NET. We’ll start by reviewing some of the fundamental concepts and terms used with IIS and ASP.NET. We’ll then describe how the Windows SharePoint Services team designed and implemented Windows SharePoint Services 3.0 to sit on top of IIS and extend the ASP.NET Framework.
The primary goal of this chapter is for you to understand the internal workings of a Web application and how it initializes the Windows SharePoint Services run-time environment. As you will see, the Windows SharePoint Services team has extended ASP.NET by replacing many of the standard components with their own.
At the end of this chapter, we will introduce application pages and discuss why they become a fundamental aspect of Windows SharePoint Services architecture. We will also walk you through the process of creating your own application pages for a custom solution and writing code behind them that accesses the Windows SharePoint Services object model.
IIS Web Sites and Virtual Directories
Both ASP.NET and Windows SharePoint Services rely on IIS 6.0 to supply the underlying listening mechanism to process incoming HTTP requests and supply a management infrastructure for launching and running worker processes on the Web server. Your understanding of how all of the pieces fit together should start with the basic concepts of an IIS Web site and virtual directories.
An IIS Web site provides an entry point into the IIS Web server infrastructure. Each IIS Web site is configured to listen for and process incoming HTTP requests that meet certain criteria. For example, an IIS Web site can be configured to handle requests coming in over a specific IP address or port number or can be routed to the Web server by using a specific host header, such as
IIS automatically creates and configures an IIS Web site named Default Web Site that listens for HTTP requests coming in over port 80 on any of the IP addresses supported on the local Web server. It is also possible to create and configure additional IIS Web sites by using the IIS Administration tools.
Each IIS Web site defines a specific URL space. For example, the standard Default Web Site defines a URL space to handle any incoming request whose URL maps to the following pattern:
http://www.Litwareinc.com/*. As you can imagine, an unlimited number of URLs can be created within this URL space. IIS processes incoming requests targeted to one of these URLs by routing them to the Default Web Site.
Each IIS Web site is configured to map to a root directory, which is a physical directory on the file system of the hosting Web server. For example, standard configuration for IIS maps the Default Web Site to a root directory located at
C:\Inetpub\wwwroot. In the most straightforward routing scenarios, IIS maps incoming HTTP requests to physical files inside the root directory. For example, IIS will respond to a request for
http://www.Litwareinc.com/page1.htm by simply loading the contents of the file located at
c:\Inetpub\wwwroot\page1.htm into memory and streaming it back to the client.
One important aspect of an IIS Web site is that it controls whether incoming requests require authentication and, if so, which authentication protocols to use. For example, the Default Web Site might be intended as a public-facing Web site for Internet users. As such, it might be configured to allow anonymous access and to support Basic Authentication. A secondary IIS Web site intended exclusively for employee use within the corporate LAN might be configured to disallow anonymous access and to support Integrated Windows Authentication instead of Basic Authentication.
In addition to IIS Web sites, IIS supports the creation and configuration of virtual directories. A virtual directory is an entity that defines a child URL space nested within the URL space of its parent IIS Web site. Like an IIS Web site, a virtual directory is configured with a root directory on the file system of the hosting Web server. IIS provides the flexibility of defining the root directory for a virtual directory at any location. For example, you could create a virtual directory within the Default Web Site with a URL space such as
http://www.Litwareinc.com/Sales. When you create this virtual directory, you can configure its root directory as a file system directory such as
IIS provides an administration utility named Internet Information Services (IIS) Manager, shown in Figure 2-1. This utility allows you to inspect, create, and configure IIS Web sites and virtual directories on the current machine. It can be started by using the shortcut Start | Administrative Tools | Internet Information Services (IIS) Manager. If you are not already familiar with this utility, you can launch it to learn how it is used to inspect and configure the properties of IIS Web sites and virtual directories.
Notice that IIS tracks configuration information about its IIS Web sites and virtual directories in a repository known as the IIS metabase. The IIS metabase lives on the file system of each front-end Web server running IIS. For example, when you create and configure an IIS Web site using the IIS administration utility, IIS tracks these changes by writing entries to the local IIS metabase.
Figure 2-1. IIS provides an administration utility to inspect and configure IIS Web sites and virtual directories
Instead of using the IIS administration utility, you can also automate the process of creating and configuring IIS Web sites and virtual directories by writing scripts or by writing managed code that programs against the IIS object model. This process is commonly done in Web farm environments when rolling out new Web sites because the identical IIS metabase setting must be applied across each front-end Web server in the farm.
ISAPI Extensions and ISAPI Filters
In the most straightforward routing scenarios, IIS simply maps an incoming request to a physical file within the root directory of an IIS Web site or virtual directory. However, IIS also supports the Internet Server Application Programming Interface (ISAPI) programming model, which provides the opportunity for more sophisticated routing scenarios. In particular, the ISAPI programming model allows you to configure an IIS Web site or virtual directory so that incoming requests trigger the execution of custom code on the Web server.
The ISAPI programming model was introduced with the original version of IIS and continues to provide the lowest level for creating custom components for IIS. The ISAPI programming model consists of two primary component types: ISAPI extensions and ISAPI filters.
An ISAPI extension is a component DLL that plays the role of an endpoint for an incoming request. The fundamental concept is that IIS can map incoming requests to a set of endpoints that trigger the execution of code within an ISAPI extension DLL. An ISAPI extension DLL must be installed on the Web server and configured at the level of either an IIS Web site or virtual directory. Configuration commonly involves associating specific file extensions with the ISAPI extensions by using an IIS application map.
While an ISAPI extension serves as an endpoint, an ISAPI filter plays the role of an interceptor. An ISAPI filter is installed and configured at the level of the IIS Web site. Once installed, an ISAPI filter intercepts all incoming requests targeting that IIS Web site. The fundamental concept is that an ISAPI filter can provide pre-processing and post-processing for each and every incoming request. ISAPI filters are typically created to provide low-level functionality for an IIS Web site, such as custom authentication and request logging.
Custom development of ISAPI components isn’t very popular these days for several reasons. First, custom ISAPI components are difficult to design, develop, and debug because they must be written in unmanaged C++ and require complicated coding techniques for things such as thread synchronization. Most developers work a level above ISAPI and utilize frameworks such as ASP and ASP.NET. While it is likely that you will never be required to write an ISAPI component, it is still important that you understand how ISAPI components fit into the big picture.
Application Pools and the IIS Worker Process
IIS provides a flexible infrastructure for managing worker processes by using application pools. An application pool is a configurable entity that allows you to control how IIS maps IIS Web sites and virtual directories to instances of the IIS worker process. Note that instances of the IIS worker process are launched using an executable named w3wp.exe, as shown in Figure 2-2.
Figure 2-2. IIS uses a device driver named HTTP.SYS to route incoming requests to the proper application pool
The routing architecture of IIS is controlled by a kernel-level device driver named http.sys. This device driver listens for incoming HTTP requests and uses information in the IIS metabase to route them to whatever instance of w3wp.exe is associated with the target application pool. If http.sys determines that the target application pool doesn’t have a running instance of w3wp.exe, it launches a new instance on demand to process the request.
Each IIS Web site and virtual directory can be configured to run in its own isolated application pool. Conversely, you can configure many different IIS Web sites and virtual directories to run in the same application pool for greater efficiency. The key observation you should make is that a tradeoff exists between isolation and efficiency. To achieve greater isolation means you must run more instances of w3wp.exe, which compromises efficiency. To achieve greater efficiency means you must map multiple IIS Web sites and virtual directories to fewer instances of the IIS worker process, which compromises isolation.
Every application pool has an important setting known as the application pool identity. The application pool identity is configured with a specific Windows user account that is either a local account on the Web server or a domain account within an Active Directory directory service domain. When http.sys launches a new instance of w3wp.exe for a specific application pool, it uses the application pool identity to initialize a Windows security token that serves as the process token. This is important because it establishes the “runs as” identity for code that runs within the IIS worker process.
By default, IIS uses the identity of the local Network Service account when you create a new application pool. However, you can configure the application pool identity by using any other user account you like. When deploying Web sites based on ASP.NET and Windows SharePoint Services, it is recommended that you configure the application pool identity with a domain account instead of the Network Service account. This is especially true in a Web farm environment when you need to synchronize the identity of an application pool across multiple front-end Web servers in the farm.
Restarting an Application Pool
When developing for ASP.NET and Windows SharePoint Services, you will occasionally find it necessary to restart the application pool that you are using to test your code. This might be the case when you need to refresh an XML file within a feature definition you are developing, or you might need to reload a new version of an assembly DLL from the Global Assembly Cache. You can restart all of the processes associated with IIS by running the following command from the command line:
You can alternatively restart just the process associated with a specific application pool by running a VB Script macro named iisapp.vbs that has been a standard part of the IIS 6.0 installation since the release of Windows Server 2003, Service Pack 1 (SP1). You must run this script by using a scripting host, such as cscript.exe. When you call cscript.exe and then include the path to iisapp.vbs, you can restart a specific application pool by passing the /a parameter along with the name of the IIS application pool.
cscript.exe c:\windows\system32\iisapp.vbs /a "DefaultAppPool"
The main advantage of using this technique is that it is faster than a full IISRESET command, which restarts all processes associated with IIS. Using this command instead of an IISRESET command can save you a few seconds here and there.
ASP.NET 2.0 Framework
The ASP.NET Framework represents a significant productivity layer on top of IIS and the ISAPI programming model. If you are familiar with ASP.NET development, you know that it provides the convenience of writing your application logic in a managed language, such as Microsoft Visual C# or Visual Basic, and working with all productivity-oriented visual designers provided by Microsoft Visual Studio. The ASP.NET Framework also provides many other valuable abstractions that assist developers in areas such as state management, data binding, navigation, and data caching.
The ASP.NET Framework is implemented as an ISAPI extension named aspnet_isapi.dll. The basic configuration for ASP.NET involves registering application maps for common ASP.NET file extensions including .aspx, .ascx, .ashx, and .asmx at the level of an IIS Web site or virtual directory. When IIS sees an incoming request targeting a file with one of these extensions, it forwards the request to aspnet_isapi.dll, which effectively passes control over to the ASP.NET Framework. The way in which the ASP.NET Framework processes a request largely depends on the extension of the target file.
The ASP.NET Framework executes the requests targeted for each IIS Web site and each virtual directory as its own independent ASP.NET application. Behind every ASP.NET application is a root directory containing a set of files. This architecture promotes a very simple x-copy style for deploying an ASP.NET application. You simply create a new virtual directory on the Web server computer and copy the ASP.NET application files into the root directory. Of course, this is a little more tedious in a Web farm environment because of the creation of a virtual directory, and the copying of the files must be duplicated over each front-end Web server in the farm.
Each ASP.NET application can be configured independently by adding a web.config file at its root directory. The web.config file is an XML-based file with configuration elements that control the behavior of various features of the ASP.NET Framework such as compilation, page rendering, and state management. A simple web.config file looks like this.
<configuration> <system.web> <customErrors mode="On" /> <httpRuntime maxRequestLength="51200" /> <authentication mode="Windows" /> <identity impersonate="true" /> <authorization> <allow users="*" /> </authorization> </system.web> </configuration>
It is important to note that the ASP.NET Framework runs each ASP.NET application with a certain level of isolation. This is true even in a scenario when you have configured multiple ASP.NET applications to run within the same IIS application pool. The ASP.NET Framework provides isolation between ASP.NET applications running inside the same instance of the IIS worker process by loading each of them into a separate .NET Framework AppDomain.
The page is one of the most valuable abstractions in the ASP.NET Framework. Developers building ASP.NET applications typically construct pages by dragging and dropping server controls onto a visual design surface in Visual Studio and modifying the properties of pages and controls by using standard property sheets. The ASP.NET Framework and Visual Studio also make it relatively simple to add logic to pages by writing managed code that executes in response to page-level and control-level events.
At a physical level, a page in an ASP.NET application is a file with an .aspx extension that resides on the Web server and is compiled into a DLL on demand by the ASP.NET runtime. Consider the following .aspx page definition that contains a server-side control and a simple event handler.
Behind the scenes, the ASP.NET Framework does quite a bit of work to compile an .aspx file into a DLL. First, it must parse the .aspx file to generate a Visual C# (or Visual Basic) source file containing a public class that inherits from the Page class that is defined within the System.Web.UI namespace inside the system.web.dll assembly. When the ASP.NET page parser generates this Page-derived class, it builds a control tree containing all of the server-side controls defined within the page file. The page parser also adds the required code to hook up any event handlers that are defined within the page.
Once the ASP.NET page parser builds the source file for an .aspx page, it can then compile it into a DLL. This compilation occurs automatically the first time the .aspx file is requested. Once the ASP.NET runtime has compiled an .aspx file into a DLL, that copy of the DLL can be used for all subsequent requests that target the same .aspx file. However, the ASP.NET runtime monitors the datetime stamp on the .aspx file and retriggers the compilation process to rebuild the DLL if it sees that the associated .aspx file has been updated.
One reason the ASP.NET Framework is so popular has to do with the convenience of server-side controls. It’s very easy to compose pages using out-of-the-box controls that ship with the ASP.NET Framework such as the validation controls, the calendar control, and controls that support data binding, such as the GridView control and the Repeater controls. Furthermore, it’s relatively simple for a developer to author custom controls and use them on pages.
ASP.NET 2.0 introduced master pages, which provide a very effective approach to page templating. In particular, a master page defines common elements that are to be used across many different pages (such as the top banner) as well as site navigation controls. The layout defined in a master page can then be used across many different pages that link to it. In ASP.NET terminology, a page that links to a master page is known as a content page. The basic relationship between a master page and its associated content pages is shown in Figure 2-3.
Figure 2-3. A master page defines a common layout and named placeholders that can be replaced within the content pages that link to the master page
For example, assume that you want to create a master page that defines the HTML layout with a banner at the top of the page. You start by creating a file with a .master extension, such as default.master. Next, you add the @Master directive at the top of the page. Below that, you define the HTML layout of the page and add in named placeholders, such as the following example.
When you want to create a content page, you create an .aspx file and add an @Page directive that contains a MasterPageFile attribute. Once you decide which of the named placeholders from the master page you would like to replace, you then define Content elements for each one. The following is a simple example of a content page that links to the default.master page shown in the preceding code and replaces the content in the placeholder named PlaceHolderMain.
Notice that when you create a content page that links to a master page, any HTML you would like to add must be written inside a Content element that points to a specific named placeholder. The page will not compile if you try to add HTML or server-side controls outside of a Content element. However, as you can see from the previous example, you can add a script block outside of a Content element and add whatever code you like.
When a master page defines a named placeholder, you are not required to replace it within a content page. Therefore, a master page can create a placeholder with default content inside. Any content page that links to that master page and does not include that named placeholder will get the default content. Another content page that links to the same master page and does include that named placeholder will override the default content, replacing it with its own custom content.
Finally, note that whoever creates a master page decides what the named placeholders will be and which contain default content. This is important when it comes to designing pages for a SharePoint site because you will be creating content pages that link to master pages created by the Windows SharePoint Services team. In this case, you must learn what placeholders the Windows SharePoint Services team has defined and what types of content are replaceable.
HTTP Request Pipeline
Underneath the productivity-centered architecture for pages and server-side controls, the ASP.NET Framework exposes the HTTP Request Pipeline for developers who like to work at a lower level. It provides the developer with a degree of control comparable with the ISAPI programming model. However, when you create a component for the HTTP Request Pipeline, you are able to write your code in a managed language such as Visual C# or Visual Basic. You can also use APIs provided by the ASP.NET Framework, which is much easier than using the ISAPI programming model.
Figure 2-4 displays a picture of the HTTP Request Pipeline and its three replaceable component types: HttpHandler, HttpApplication, and HttpModule. As requests come in, they are queued up and assigned to a worker thread that then processes the request by interacting with each of these component types.
Figure 2-4. The HTTP Request Pipeline allows developers to replace components such as HttpHandler, HttpApplication, and HttpModule
The ultimate destination of any request is the endpoint, which is modeled in the HTTP Request Pipeline by using an HttpHandler class, which implements the IHttpHandler interface. As a developer, you can create a custom HttpHandler component and plug it into the HTTP Request Pipeline by adding configuration elements to the web.config file.
The HTTP Request Pipeline places an HttpApplication component in front of the HttpHandler. On an application-wide basis, incoming requests are always routed through the HttpApplication before they reach the target HttpHandler, thus giving the HttpApplication the ability to pre-process any request no matter which HttpHandler it is being routed to. This preprocessing stage is handled through a series of events that are defined inside the HttpApplication class such as BeginRequest, AuthenticateRequest, and AuthorizeRequest.
In situations when you don’t want to use a custom HttpApplication component, the ASP.NET Framework initializes the HTTP Request Pipeline with a standard HttpApplication object that provides default behavior. However, you can replace this standard component by creating a file named global.asax and placing it in the root directory of the hosting ASP.NET application. For example, you can create a global.asax that looks like the following.
The third replaceable component type in the HTTP Request Pipeline is the HttpModule. The HttpModule is similar to the HttpApplication component in that it is designed to handle events defined by the HttpApplication class and is processed before control is passed to any HttpHandler classes. For example, you can create a custom HttpModule component to handle request-level events such as BeginRequest, AuthenticateRequest, and AuthorizeRequest. As with the HttpHandler, an HttpModule class is defined with an interface. You can create a class that implements the IHttpModule interface and plug it into the HTTP Request Pipeline by adding configuration elements to the web.config file.
Whereas custom HttpApplication components can be defined as simple text files with an .asax extension, custom HttpModule components are always compiled as classes within assembly DLLs. To add a custom HttpModule component into the HTTP Request Pipeline, you then add entries into a web.config file.
While an HttpApplication component and an HttpModule component are similar in what they do, the HttpModule contains a few noteworthy differences. First, you are not limited to one HttpModule per application as you are with the HttpApplication components. The web.config file for an ASP.NET application can add in several different HttpModule components. Second, HttpModule components can be configured at the machine level. In fact, the ASP.NET Framework ships with several different HttpModule components that are automatically configured at the machine level to provide ASP.NET functionality for things such as Windows authentication, Forms authentication, and output caching.
The final component that we want to discuss with respect to the HTTP Request Pipeline is HttpContext. As ASP.NET initializes a request to send to the HTTP Request Pipeline, it creates an object from the HttpContext class and initializes it with important contextual information.
From a timing perspective, it’s important to see that ASP.NET creates this object before any custom code inside the HTTP Request Pipeline has a chance to begin execution. This means that you can always program against the HttpContext object and the child objects that it contains, such as Request, User, and Response. Whenever you are authoring a component that is to execute within the HTTP Request Pipeline, you can write code that looks like the following.
Further Reading About ASP.NET
We encourage you to learn as much as you can about ASP.NET 2.0 because it will make you a stronger Windows SharePoint Services 3.0 developer. Many advanced ASP.NET techniques are readily available when you are creating solutions for Windows SharePoint Services 3.0. The following list presents a few of our favorite titles.
- Programming ASP.NET 2.0: Core Reference, by Dino Esposito (Microsoft Press, 2006)
- Programming ASP.NET 2.0 Applications: Advanced Topics, by (Microsoft Press, 2006)
- Essential ASP.NET 2.0, 2nd Edition, by and ( , 2007)
Windows SharePoint Services Integration with ASP.NET
As you build your understanding of how Windows SharePoint Services integrates with ASP.NET, you should begin by thinking through the high-level Windows SharePoint Services design goals that were created to add value on top of the ASP.NET Framework. Windows SharePoint Services adds significant value on top of ASP.NET in environments that require sites to be continuously created, updated, and deleted. Windows SharePoint Services also adds a dimension of site element provisioning on top of ASP.NET that allows site administrators to quickly create pages, lists, and document libraries within the context of a site.
Windows SharePoint Services integrates with ASP.NET at the level of the IIS Web site. Each IIS Web site in which you intend to host SharePoint sites must go through a one-time transformation process in which it is configured to become what Windows SharePoint Services terminology refers to as a Web application. This transformation process involves adding IIS metabase entries and a SharePoint-specific web.config file to the root directory of the hosting IIS Web site. Once the transformation is completed, Windows SharePoint Services extends the routing architecture of IIS and ASP.NET to properly route all incoming requests through the Windows SharePoint Services runtime.
The next section of this chapter discusses the nuts and bolts of how a Web application is configured. However, before you dive into these details, we want you to make an important observation. In particular, we want you to consider how the Web application as a whole fits into the bigger picture of Windows SharePoint Services architecture from the perspective of manageability and scalability.
The creation of a Windows SharePoint Services Web application is a significant administration task that requires farm-level administrative privileges. Creating a Web application requires a significant number of changes to the file system and the IIS metabase on each front-end Web server. In a Web farm environment, these changes are automatically mirrored across each front-end Web server in the farm by the Windows SharePoint Services runtime. This step of creating a Web application is only required when initially installing and configuring Windows SharePoint Services.
Once a Web application is created, it is no longer necessary to touch the file system or IIS metabase of the front-end Web server when creating, updating, and deleting sites or site collections. The Windows SharePoint Services architecture makes it possible to provision new sites and site collections simply by adding entries to the configuration database and a content database. It is this aspect of the Windows SharePoint Services architecture that gives it significant management and provisioning advantages over ASP.NET. This added level of manageability is even more pronounced in a Web farm environment.
Two primary ways exist to create a Web application by using either the Windows SharePoint Services Central Administration Application or the stsadm.exe command-line utility. First, you can create a Web application by converting an existing IIS Web site. Alternatively, you can create a new Web application from scratch and let Windows SharePoint Services create the new IIS Web site for you behind the scenes. In either case, Windows SharePoint Services configures the resulting IIS Web site by adding an IIS application map and creating several virtual directories. Windows SharePoint Services also copies a global.asax file and web.config file to the root directory of the hosting IIS Web site.
Windows SharePoint Services must add an IIS application map to each Web application to ensure that each and every incoming request is initially routed to the ASP.NET runtime. Remember that the default configuration for ASP.NET only registers application maps for requests with well-known ASP.NET file extensions such as .aspx, ascx, .ashx, and .asmx. Therefore, Windows SharePoint Services configures the hosting IIS Web site with a wildcard application map to route all incoming requests to aspnet_isapi.dll, including those requests with non-ASP.NET extensions such as .doc, .docx, and .pdf.
Because every request targeting a Web application is routed through aspnet_isapi.dll, the request gets fully initialized with ASP.NET context. Furthermore, its processing behavior can be controlled by using a custom HttpApplication object and adding configuration elements to the web.config file. The Windows SharePoint Services team uses standard ASP.NET techniques to extend the HTTP Request Pipeline by using several custom components, as shown in Figure 2-5.
First, you can see that Windows SharePoint Services configures each Web application with a custom HttpApplication object by using the SPHttpApplication class. Note that this class is deployed in the Windows SharePoint Services system assembly Microsoft.SharePoint.dll. Windows SharePoint Services integrates this custom application class by creating a custom global.asax file at the root of the Web application that inherits from SPHttpApplication.
Figure 2-5. Windows SharePoint Services extends the standard ASP.NET HTTP Request Pipeline with its own custom components
In addition to including a custom HttpApplication object, the Windows SharePoint Services architecture uses a custom HttpHandler and a custom HttpModule. These two SharePoint-specific components are integrated into the HTTP Request Pipeline for a Web application using standard entries in the web.config file. Examine the following XML fragment that is taken from the standard web.config file used by a Windows SharePoint Services 3.0 Web application.
<configuration> <system.web> <httpHandlers> <remove verb="GET,HEAD,POST" path="*" /> <add verb="GET,HEAD,POST" path="*" type="Microsoft.SharePoint.ApplicationRuntime.SPHttpHandler, ..." /> </httpHandlers> <httpModules> <clear /> <add name="SPRequest" type="Microsoft.SharePoint.ApplicationRuntime.SPRequestModule, ..." /> <!-- other standard ASP.NET httpModules added back in --> </httpModules> </system.web> </configuration>
The Windows SharePoint Services team members have created their own HttpModule named SPRequestModule to initialize various aspects of the Windows SharePoint Services runtime environment. You can see that the standard Windows SharePoint Services web.config file configures SPRequestModule so that it is the first HttpModule to respond to application-level events in the HTTP Request Pipeline of ASP.NET. If you examine the web.config file for a Windows SharePoint Services Web application, you will see that Windows SharePoint Services adds back in several of the standard HttpModule components from the ASP.NET Framework that deal with things such as output caching and various types of authentication.
The standard Windows SharePoint Services web.config file also registers an HttpHandler named SPHttpHandler and configures it with a path of “*”. This allows Windows SharePoint Services to provide the SPHttpHandler class as a single endpoint for all incoming requests.
As you can see, the architecture of Windows SharePoint Services is made possible through extending the HTTP Request Pipeline. This allows Windows SharePoint Services to fully leverage the underlying capabilities of the ASP.NET Framework while also taking over control of each and every request that targets a Web application.
Standard web.config File for a Web Application
In the previous section of this chapter, you saw that the web.config file for a Web application contains standard ASP.NET configuration elements. However, Windows SharePoint Services goes further by extending the standard ASP.NET web.config file format with a custom SharePoint section. Examine the following XML fragment that shows the SharePoint section of the web.config file and the elements within the configSections element that are required by ASP.NET for extended configuration information.
<configuration> <configSections> <sectionGroup name="SharePoint"> <section name="SafeControls" type="..." /> <section name="RuntimeFilter" type="..." /> <section name="WebPartLimits" type="..." /> <section name="WebPartCache" type="..." /> <section name="WebPartWorkItem" type="..." /> <section name="WebPartControls" type="..." /> <section name="SafeMode" type="..." /> <section name="MergedActions" type="..." /> <section name="PeoplePickerWildcards" type="..." /> </sectionGroup> </configSections> <SharePoint> <SafeMode /> <WebPartLimits /> <WebPartCache /> <WebPartControls /> <SafeControls /> <PeoplePickerWildcards /> <MergedActions /> <BlobCache /> <RuntimeFilter /> </SharePoint> </configuration>
The configuration elements that are nested within the SharePoint section are read by various components of the Windows SharePoint Services runtime. For each element nested within the SharePoint section, there is a section element inside the configSections element that defines what configuration class is used to read this information at run time. This makes it possible for various components of the Windows SharePoint Services runtime to read this SharePoint-specific configuration information while processing a request. You will see several development techniques throughout this book that require adding or changing elements within the SharePoint section of the web.config file.
One of the strengths of Windows SharePoint Services over ASP.NET is its ability to provision and customize pages within a site without having to make any changes to the local file system of the front-end Web server. This capability of Windows SharePoint Services to provision and customize pages is made possible by storing customized versions of .aspx files and .master files inside the content database and retrieving them on demand when they are needed to process an incoming page request.
Consider a simple example of how page customization works in Windows SharePoint Services. Imagine that you would like to modify the HTML layout of the home page (default.aspx) for a particular site by using the Microsoft Office SharePoint Designer. When you modify and save a page using SharePoint Designer, Windows SharePoint Services writes the entire contents of this customized page definition to the content database. After that point, when the same page is requested, Windows SharePoint Services must retrieve the contents of this customized page definition from the content database and pass it along to the ASP.NET runtime for parsing. We will now explain the architectural details that make this possible.
ASP.NET 2.0 introduced a new pluggable component type known as a virtual path provider. The idea behind a virtual path provider is that it abstracts the details of where page files are stored away from the ASP.NET runtime. By creating a custom virtual path provider, a developer can write a custom component that retrieves ASP.NET file types, such as .aspx and .master files, from a remote location, such as a Microsoft SQL Server database. Once a virtual path provider retrieves the contents of an .aspx page, it can pass it along to the ASP.NET runtime for parsing.
The Windows SharePoint Services team created a virtual path provider named SPVirtualPathProvider that is integrated into every Web application. The SPVirtualPathProvider class is integrated into the ASP.NET request handling infrastructure by the SPRequestModule. More specifically, the SPRequestModule component contains code to register the SPVirtualPathProvider class with the ASP.NET Framework as it does its work to initialize a Web application. Figure 2-6 displays a diagram that depicts the role of the SPVirtualPathProvider.
As you can see, the SPVirtualPathProvider is able to retrieve an ASP.NET page file from the content database, such as default.aspx, and then pass it along to the ASP.NET page parser. The SPVirtualPathProvider class works together with another class named the SPPageParserFilter to supply processing instructions to the ASP.NET page parser. For example, the SPPageParserFilter component controls whether the ASP.NET page parser compiles the ASP.NET page into an assembly DLL or whether it processes the page in a no-compile mode that is introduced with ASP.NET 2.0. In the next chapter, you will see how to add an entry into the web.config file that tells the SPPageParserFilter how to process pages.
Figure 2-6. Windows SharePoint Services employs a custom virtual path provider to employ the .aspx page parser supplied by ASP.NET 2.0
The SPVirtualPathProvider component plays a critical role in the overall Windows SharePoint Services architecture. As you can see, it provides the foundation for supporting page customization. It also supports an important optimization known as page ghosting, which is a key factor in allowing a server farm to scale out to tens of thousands of pages across all the sites within a farm. Let me provide a quick example to illustrate how page ghosting works.
Imagine that you have just created 100 new SharePoint sites from the Blank Site template. If none of these sites requires a customized version of its home page (default.aspx), would it still make sense to copy the exact same page definition file into the content database 100 times? The answer to this question is obviously no. Fortunately, pages within a SharePoint site such as default.aspx are based on page templates that live on the file system of the front-end Web server. Page templates are used to provision page instances within the context of a site, such as the page that is accessible through a specific URL like
When a page instance is initially provisioned from a page template, Windows SharePoint Services doesn’t need to store a copy of it in the content database because Windows SharePoint Services can load the page template from the file system of the Web server and use it to process any request for an uncustomized page instance. Therefore, you can say that page ghosting describes the act of processing a request for an uncustomized page instance by using a page template loaded into memory from the file system of the front-end Web server.
Page ghosting is valuable because it eliminates the need to transfer the contents of a page definition file from the SQL Server computer with the content database to the front-end Web server computer. Page ghosting also makes it possible to process the home pages for thousands of different sites by using a single page template that is compiled into an assembly DLL and loaded into memory in the IIS worker process just once per Web application. Both of these optimizations are key factors in the scalability of Windows SharePoint Services in high-traffic environments running thousands or tens of thousands of sites.
When you modify a page and save a customized version of it in the content database using SharePoint Designer, you eliminate the possibility of page ghosting. Instead, the provided SPVirtualPathProvider must retrieve the customized version of the page from the content database, as shown in Figure 2-6. For this reason, customized pages are sometimes referred to as unghosted pages.
Now that you understand how Windows SharePoint Services processes requests for both ghosted and unghosted pages, you should observe the important role that is played by the SPVirtualPathProvider. It is the SPVirtualPathProvider that determines whether the page being requested has been customized. The SPVirtualPathProvider makes the decision whether to process a page as a ghosted or an unghosted page. Furthermore, all aspects of page ghosting and unghosting are hidden from the ASP.NET runtime and represent a value-added dimension of Windows SharePoint Services.
Page Parsing in Windows SharePoint Services 2.0
The previous version of Windows SharePoint Services was based on ASP.NET 1.1, which did not provide any equivalent to the virtual path provider model introduced in ASP.NET 2.0. Consequently, the Windows SharePoint Services team created their own .aspx page parser to parse customized .aspx files after they are retrieved from the content database. Unfortunately, the .aspx parser created by the Windows SharePoint Services team for Windows SharePoint Services 2.0 does not support many of the richer features offered by the ASP.NET page parser, such as the ability to host user controls. The new architecture introduced in Windows SharePoint Services 3.0, which includes the SPVirtualPathProvider and the ASP.Net page parser, should be seen as one of the more significant architectural enhancements over Windows SharePoint Services 2.0.
Virtual Directories Within a Web Application
When Windows SharePoint Services converts an IIS Web site into a Web application, it creates several virtual directories. These virtual directories, including the _controltemplates directory, the _layouts directory, the _vti_bin directory, and the _wpresources directory, are used by various aspects of the Windows SharePoint Services runtime. These virtual directories can be seen by examining a Web application using the IIS Manager tool, as shown in Figure 2-7.
Figure 2-7. An IIS Web site configured as a Web application has four standard virtual directories including the _layouts directory
As you can see from the image in Figure 2-7, each of the virtual directories within a Web application maps to a physical directory on the file system of the front-end Web server under the following path.
c:\program files\common files\microsoft shared\web server extensions
Each of these virtual directories plays a special role in the overall Windows SharePoint Services architecture. For example, the _vit_bin directory provides Windows SharePoint Services with a way to expose DLLs and .asmx Web service files at a path within the URL space of a Web application. The _controltemplates directory provides a dedicated repository for deploying ASP.NET user controls that can be used within pages. The _wpresources virtual directory provides a repository for resource files that are deployed along with Web Parts.
The one virtual directory of a Web application that we want to discuss in greater depth in this chapter is the _layouts directory because it provides the foundation for a special type of page known as an application page. Application pages are served up from the _layouts directory and provide a special type of functionality that is discussed in the next section.
Site Pages versus Application Pages
Some pages in a SharePoint site, such as the home page (default.aspx), support user customization by using tools such as the SharePoint Designer. Pages that support user customization are known as site pages. While the support for the customization of site pages provides a great deal of flexibility, it also has a downside. To support page customization without adversely affecting scalability, Windows SharePoint Services must employ the page ghosting scheme discussed earlier in this chapter. However, page customization can still have a measurable impact on scalability.
Imagine a large Windows SharePoint Services environment with a Web application running thousands of sites. What would happen if the site administrator of each site modified the site’s home page with the SharePoint Designer? Every one of these site pages would become unghosted (customized). This would negatively impact scalability by forcing the front-end Web server to retrieve each page separately from the content database. Each page would also have to be individually parsed and loaded into memory.
Also consider the fact that once a site page has been customized, a copy must be stored in the content database. This brings up a security concern. Imagine a situation in which a malicious user who has been granted site administrator permissions within a site collection tries to mount an attack by writing in-line code within a customized version of a site page. This security concern is mitigated in Windows SharePoint Services by having a default policy that prohibits in-line scripting in site pages. The default policy also runs site pages in a no-compile mode, which means they are not compiled into DLLs.
The key point here is that customization support for site pages brings with it performance concerns and security issues. As noted earlier, the Windows SharePoint Services architecture provides another type of page known as an application page. One of the key characteristics of an application page is that it does not support customization. Therefore, application pages can circumvent some of the main performance concerns and security issues associated with site pages.
The standard Site Settings page (settings.aspx) is a good example of an application page. It can be accessed from any site, yet it does not support customization. Application pages, such as settings.aspx, are deployed as physical files on the file system of the front-end Web server in a directory at the following path.
c:\program files\common files\microsoft shared \web server extensions\12\TEMPLATE\LAYOUTS
Note that the physical \LAYOUTS directory is mapped to the virtual _layouts directory whenever Windows SharePoint Services creates a new Web application. By using this mapping scheme along with some additional processing logic, the Windows SharePoint Services runtime can make each application page accessible within the context of any site in the farm. For example, assume that there are three different sites in a server farm accessible through the following three URLs.
http://Litwareinc.com http://Litwareinc.com/sites/Vendors http://Litwareinc.com:1001/sites/Accounting
An application page, such as settings.aspx, can be accessed by adding its relative path within the _layouts directory to the end of a site’s URL. For example, you can access the Site Setting page by using any of the following three URLs:
http://Litwareinc.com/_layouts/settings.aspx http://Litwareinc.com/sites/Vendors/_layouts/settings.aspx http://Litwareinc.com:1001/sites/Accounting/_layouts/settings.aspx
Because there is only one version of an application page scoped at the farm level, it can be compiled into a single DLL and loaded into memory once for each Web application. You never have to worry about the existence of different versions of an application page for different sites. Furthermore, application pages are not subject to attack from users who have permissions to customize site pages. Therefore, Windows SharePoint Services does not prohibit them from containing in-line code.
Application pages are used extensively by the Windows SharePoint Services team to supply much of the standard functionality for provisioning and administrating sites as well as the elements inside them. Figure 2-8 displays an image of the physical \LAYOUTS directory on the front-end Web server that Windows SharePoint Services maps to the _layouts directory. As you can see, the standard installation of Windows SharePoint Services 3.0 includes many different application pages, including settings.aspx.
If you open and inspect the source code for one of the standard Windows SharePoint Services application pages, you see that it links to a master page in the _layouts directory named application.master. In the next section, we will discuss the creation of custom application pages. When you create your own custom application pages, you might want to follow suit and create them to link to the application.master file as well.
Figure 2-8. The \LAYOUTS directory contains application pages that are accessible from within any site in the farm
Let us now summarize the difference between site pages and application pages. Site pages support page customization. Examples of site pages include the home page (default.aspx) for a site as well as the pages associated with lists and document libraries, such as AllItems.aspx, NewForm.aspx, and EditForm.aspx. The fact that site pages support customization provides flexibility but can also impact performance and scalability. Site pages do not support in-line code under the default security policy enforced by Windows SharePoint Services.
Application pages do not support customization, which gives them two distinct advantages over site pages. First, each application page is always compiled into a single DLL so that it performs and scales better than a site page. Second, application pages are allowed to have in-line code. Now that you have a basic understanding of what constitutes an application page, it will be worthwhile to see what is involved in creating your own application pages for a custom solution.