As you build your understanding of how WSS integrates with ASP.NET, you should begin by thinking through the high-level WSS design goals that were created to add value on top of the ASP.NET Framework. WSS adds significant value on top of ASP.NET in environments that require sites to be continuously created, updated, and deleted. WSS 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.
WSS integrates with ASP.NET at the level of the IIS Web site. Each IIS Web site in which you intend to host WSS sites must go through a one-time transformation process in which it is configured to become what WSS terminology refers to as a Web application. This transformation process involves adding IIS metabase entries and a WSS-specific web.config file to the root directory of the hosting IIS Web site. Once the transformation is completed, WSS extends the routing architecture of IIS and ASP.NET to properly route all incoming requests through the WSS 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 WSS architecture from the perspective of manageability and scalability.
The creation of a WSS 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 WSS runtime. This step of creating a Web application is only required when initially installing and configuring WSS.
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 WSS 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 WSS 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 WSS 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 WSS create the new IIS Web site for you behind the scenes. In either case, WSS configures the resulting IIS Web site by adding an IIS application map and creating several virtual directories. WSS also copies a global.asax file and web.config file to the root directory of the hosting IIS Web site.
WSS 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, WSS 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 WSS team uses standard ASP.NET techniques to extend the HTTP Request Pipeline by using several custom components, as shown in Figure 2-5.
Figure 2-5: WSS extends the standard ASP.NET HTTP Request Pipeline with its own custom components.
First, you can see that WSS configures each Web application with a custom HttpApplication object by using the SPHttpApplication class. Note that this class is deployed in the WSS system assembly Microsoft.SharePoint.dll. WSS integrates this custom application class by creating a custom global.asax file at the root of the Web application that inherits from SPHttpApplication.
<@Application Inherits="Microsoft.SharePoint.ApplicationRuntime.SPHttpApplication" >
In addition to including a custom HttpApplication object, the WSS architecture uses a custom HttpHandler and a custom HttpModule. These two WSS-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 WSS 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 WSS team members have created their own HttpModule named SPRequestModule to initialize various aspects of the WSS runtime environment. You can see that the standard WSS 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 WSS Web application, you will see that WSS 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 WSS web.config file also registers an HttpHandler named SPHttpHandler and configures it with a path of "*". This allows WSS to provide the SPHttpHandler class as a single endpoint for all incoming requests.
As you can see, the architecture of WSS is made possible through extending the HTTP Request Pipeline. This allows WSS 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.
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, WSS 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 WSS 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 WSS runtime to read this WSS-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 WSS 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 WSS 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 WSS. 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, WSS writes the entire contents of this customized page definition to the content database. After that point, when the same page is requested, WSS 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 WSS 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.
Figure 2-6: WSS employs a custom virtual path provider to employ the .aspx page parser supplied by ASP.NET 2.0.
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.
The SPVirtualPathProvider component plays a critical role in the overall WSS 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 WSS 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 WSS 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 WSS 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 http://litwareinc.com/default.aspx.
When a page instance is initially provisioned from a page template, WSS doesn’t need to store a copy of it in the content database because WSS 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 WSS 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 WSS 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 WSS.
The previous version of WSS 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 WSS 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 WSS team for WSS 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 WSS 3.0, which includes the SPVirtualPathProvider and the ASP.Net page parser, should be seen as one of the more significant architectural enhancements over WSS 2.0.
When WSS 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 WSS 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 WSS architecture. For example, the _vit_bin directory provides WSS 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.
Some pages in a WSS 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, WSS 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 WSS 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. 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 WSS 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 WSS 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 WSS creates a new Web application. By using this mapping scheme along with some additional processing logic, the WSS 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 WSS farm accessible through the following three URLs:
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:
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, WSS does not prohibit them from containing in-line code.
Application pages are used extensively by the WSS 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 WSS maps to the _layouts directory. As you can see, the standard installation of WSS 3.0 includes many different application pages, including settings.aspx.
Figure 2-8: The \LAYOUTS directory contains application pages that are accessible from within any site in the farm.
If you open and inspect the source code for one of the standard WSS 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.
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 WSS.
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 understand 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.