Chapter 3. ASP.NET Configuration

Computers are useless. They can only give you answers.

Pablo Picasso

The .NET Framework defines a tailor-made, XML-based API to access configuration files and, in doing so, forces developers to adopt a common, rich, and predefined schema for storing application settings. In the more general context of the .NET configuration scheme, ASP.NET applications enjoy specific features such as a hierarchical configuration scheme that allows settings inheritance and overriding at various levels: machine, application, or specific directories.

Configuration files are typically created offline or during the development of the application. They are deployed with the application and can be changed at any time by administrators. Changes to such critical files are promptly detected by the ASP.NET runtime, Internet Information Services (IIS), or both, and they typically cause a restart of the worker process. ASP.NET pages can use the classes in the System.Configuration namespace to read from, and to write to, configuration files.

In this chapter, I’ll specifically delve into the ASP.NET configuration machinery. You’ll see how to fine-tune the ASP.NET runtime and review the whole collection of parameters you can set for an individual application.

The ASP.NET Configuration Hierarchy

Configuration files are standard XML files that rigorously follow a given schema. The schema defines all possible settings for machine and application files. Configuration in ASP.NET is hierarchical by nature and is based on a unique, machine-specific file known as the machine.config file plus a number of web.config files. The syntax of machine.config and web.config files is identical.

Note

ASP.NET protects its configuration files from direct Web access by instructing IIS to block browser access to configuration files. An HTTP access error 403 (forbidden) is returned to all browsers that attempt to request a .config resource as a URL. At least, this was considered to be true for a few years. In September 2010, an ASP.NET vulnerability was discovered and fixed by Microsoft via a security patch. You can read about it at http://weblogs.asp.net/scottgu/archive/2010/09/18/important-asp-net-security-vulnerability.aspx. The article includes a link to the patch, which is also available through standard Windows Update channels. Why is that important here? One of the effects of the vulnerability was that it fooled a system HTTP handler to return the content of any file being requested, including web.config.

Configuration Files

The ASP.NET runtime processes configuration information hierarchically, proceeding from a root common to all applications on the machine—machine.config—down to all the web.config files found in the various folders of the particular application.

Note

The machine.config file is located in the CONFIG directory under the ASP.NET installation folder. The installation folder is located under the Windows directory at the following path: Microsoft.NETFramework[version]. For the .NET Framework 4, the version folder is v4.0.30319. If you take a look at the contents of the CONFIG directory, you’ll find three similar files: machine.config, machine.config.default, and machine.config.comments. Provided for educational purposes, the latter two files provide the description and default values of each configuration section. To gain a bit of performance, and a lot of readability, the contents of the machine.config file contain only the settings that differ from their defaults.

The Tree of Configuration Files

When an ASP.NET application starts, all configurable parameters are set to the default values defined in machine.config. These values can be overridden in the first place by a web.config file placed in the root folder of the application. The web.config file can also add new application-specific settings. In theory, a root web.config file can also clear all the settings in the original machine configuration and replace them altogether. However, in practice it is rare that you would reconfigure ASP.NET for your application to this extreme.

You can also define additional web.config files in child folders to apply other settings to all the resources contained in the subtree rooted in the folder. Also in this case, the innermost web.config can overwrite, restrict, or extend the settings defined at upper levels. Figure 3-1 illustrates how ASP.NET processes system and application settings for each page in the Web site.

The hierarchical nature of ASP.NET configuration.

Figure 3-1. The hierarchical nature of ASP.NET configuration.

Configuring the machine file is an administrative task and should be performed with the server offline when the application is deployed or during periodical maintenance. Application settings can be changed on the fly administratively or even programmatically. Usually, changes to the application’s configuration file result in a process recycling. However, in IIS 7 application pools can be configured to make recycling after a configuration change optional.

Important

Only in very special cases should the application write to its web.config file. If you need to persist some data on the server (for example, user profile data), you should take advantage of cookies or, better yet, the user profile API or some custom form of storage. The need for writing to a configuration file should be taken as an alarm bell that warns you against possible bad design choices. ASP.NET comes with a set of tailor-made classes, maps all the feasible sections and nodes in the configuration schema, and exposes methods to read and write. The primary role of configuration files is just the overall configuration of the system, namely a set of options that can be changed offline without recompiling the system.

The Configuration Schema

All configuration files have their root in the <configuration> element. Table 3-1 lists the main first-level children of the <configuration> element. Each node has a specified number of child elements that provide a full description of the setting. For example, the <system.web> element optionally contains the <authorization> tag, in which you can store information about the users who can safely access the ASP.NET application.

Table 3-1. Main Children of the <configuration> Element

Element

Description

<appSettings>

Contains custom application settings.

<configSections>

Describes the configuration sections for custom settings. If this element is present, it must be the first child of the <configuration> node.

<connectionStrings>

Lists predefined connection strings that are useful to the application.

<configProtectedData>

Contains ciphered data for sections that have been encrypted.

<runtime>

Run-time settings schema; describes the elements that configure assembly binding and run-time behavior such as probing and assembly redirect.

<startup>

Startup settings schema; contains the elements that specify which version of the common language runtime (CLR) must be used.

<system.diagnostics>

Describes the elements that specify trace switches and listeners that collect, store, and route messages.

<system.net>

Network schema; specifies elements to indicate how the .NET Framework connects to the Internet, including the default proxy, authentication modules, and connection parameters.

<system.runtime.remoting>

Settings schema; configures the client and server applications that exploit the .NET Remoting.

<system.serviceModel>

Contains configuration settings for Windows Communication Foundation (WCF) services being used by the ASP.NET application.

<system.web>

The ASP.NET-specific configuration section; it contains the elements that control all aspects of the behavior of an ASP.NET application.

<system.web.extensions>

Contains elements that configure ASP.NET AJAX capabilities and services and control their behavior.

<system.webServer>

Specifies settings for the IIS 7 Web server (and newer versions) that configure the host environment for the ASP.NET application.

Because we’re discussing ASP.NET applications, in this chapter I’ll focus primarily on the <system.web> section, with a look at <system.webServer>. I’ll cover <system.web.extensions> later on in Chapter 20, which is dedicated to AJAX programming. Other sections for which you’ll find significant coverage here are <connectionStrings> and <configProtectedData>. However, this doesn’t mean that, as an ASP.NET developer, you’ll never be using other sections—most certainly not!

For example, the <configSections> element defines the sections that will be used to group information in the rest of the document. The <appSettings> element contains user-defined nodes whose structure has been previously defined in the <configSections> node. You might need to interact with the <system.diagnostics> section if you want to use a custom trace listener that logs its results to an application-defined file.

Another section that is often found in the configuration of ASP.NET applications is <system.serviceModel>. The section is used to store settings about WCF services your ASP.NET application is going to use. Settings typically include binding information (transportation, security, credentials) and endpoint details (URL, contract, operations).

Sections and Section Groups

All sections used in a configuration file must be declared in the initial <configSections> section. The following code snippet demonstrates how the <system.web> section is declared in machine.config:

<configSections>
    <sectionGroup name="system.web"
            type="System.Web.Configuration.SystemWebSectionGroup, ...">
        <section name="authentication"
            type="System.Web.Configuration.AuthenticationSection, ..."
            allowDefinition="MachineToApplication" />
        ...
    </sectionGroup>
</configSections>

The <sectionGroup> element has no other role than marking and grouping a few child sections, thus creating a sort of namespace for them. In this way, you can have sections with the same name living under different groups. The <section> element takes two attributes: name and type. The name attribute denotes the name of the section being declared. The type attribute indicates the name of the managed class that reads and parses the contents of the section from the configuration file. The value of the type attribute is a comma-separated string that includes the class and full name of the assembly that contains it.

The <section> element also has two optional attributes: allowDefinition and allowLocation. The allowDefinition attribute specifies which configuration files the section can be used in. Feasible values for the allowDefinition attribute are listed in Table 3-2.

Table 3-2. Values for the allowDefinition Attribute

Value

Description

Everywhere

The section can be used in any configuration file. (Default.)

MachineOnly

The section can be used only in the machine.config file.

MachineToApplication

The section can be used in the machine.config file and in the application’s web.config file. You cannot use the section in web.config files located in subdirectories of the virtual folder.

The allowLocation attribute determines whether the section can be used within the <location> section. The <location> section in a machine.config file allows you to apply the specified machine-wide settings only to the resources below a given path. (I’ll say more about the <location> section shortly.)

Many sections in the configuration files support three special elements, named <add>, <remove>, and <clear>. The <add> element adds a new setting to the specified section, while <remove> removes the specified one. The <clear> element clears all the settings that have previously been defined in the section. The <remove> and <clear> elements are particularly useful in ASP.NET configuration files in which a hierarchy of files can be created. For example, you can use the <remove> element in a child web.config file to remove settings that were defined at a higher level in the configuration file hierarchy.

The <remove> and <clear> elements don’t affect the actual data stored in the configuration file. Removing a section doesn’t erase the related data from the file, it simply removes the data from the in-memory tree of settings that ASP.NET builds and maintains for an application.

Note

Sections are a necessary syntax element in configuration files. However, you don’t need to declare sections in all application-specific web.config files. When processing a web.config file, in fact, ASP.NET builds a configuration tree starting from the root machine.config file. Because all standard sections are already declared in the machine.config file that ships with the .NET Framework, your application needs to declare only custom sections you plan to use. Finally, bear in mind that an exception is thrown if a configuration section lacks a corresponding entry in the <configSections> section and when the layout of the data does not match the declaration.

Let’s start our tour of the configuration schema with a closer look at the <location> section.

The <location> Section

The <location> section serves one main purpose in two distinct scenarios. The section provides an alternative technique to apply different settings to various parts of an application. You typically employ the <location> section to apply different settings to subdirectories of the same application and to configure distinct applications installed on the same machine.

When defined inside an application’s root web.config file, it allows you to apply different settings to different subdirectories. Instead of defining child web.config files, you can create a single web.config file in the root folder and specify settings on a per-directory basis. Basically, the <location> element lets you create embedded configuration sections associated with a particular directory. From a functional point of view, this is equivalent to having a web.config file in each directory.

When defined inside the machine.config file, or in a site’s root web.config file, the <location> section enables you to specify different machine-wide settings for various Web applications. Used in this way, the section turns out to be an extremely powerful tool to let multiple applications apply individual machine-wide settings in an ISP scenario.

Important

Note the difference between the application’s root web.config file and the site’s root web.config file. The application’s root configuration file is the web.config file you find in the application’s root folder. You use this file to adapt ASP.NET settings to the needs of the particular application and its subdirectories. In contrast, the site’s root web.config file is located in the same folder as machine.config, and therefore is well outside the Web space of any deployed applications. This file is a sort of appendix of machine.config and should be used as an additional level of settings personalization. A <location> element defined in this file can be scoped to any applications on the machine. A <location> element without the path attribute will affect all applications in the machine.

Centralized Configuration

The <location> section has two attributes: Path and allowOverride. The Path attribute represents the virtual path to which the embedded settings apply. The following snippet shows how it works. The code shown is taken from a web.config file. Note that the name of the folder must be relative and should not begin with slashes, backslashes, or dots.

<configuration>
    <system.web>
        <!-- Settings for the application go here -->
    </system.web>

    <location path="Reserved">
        <system.web>
            <!-- Settings for the /Reserved folder go here -->
        </system.web>
    </location>
</configuration>

The defining characteristic of this approach is that you have a single, centralized web.config file to maintain and can still configure subdirectories individually and independently. This feature saves you from the burden of maintaining several web.config files, but it also introduces some unpleasant side effects that in the long run can turn out to be quite harsh. For example, any change to the file results in a new compilation for all the pages in the application. If you maintain distinct web.config files, the compilation occurs only for the pages really affected by the change.

Note

If the path attribute is omitted in the <location> element, the embedded settings will apply to all subfolders of the application in the case of an application’s root web.config. Settings will affect all installed applications on the server machine if the <location> element that is missing the path attribute is found in the site’s root web.config or machine.config.

Machinewide Settings

Used within the machine.config file or the site’s root web.config file, the <location> element lets you specify different machinewide settings for all the Web applications hosted on the server machine. Note that in this case, though, you must indicate the name of the application you’re configuring prefixed by the IIS name of the Web site. The Web site name is read in the IIS Manager. The following script applies to the YourApp application in the default Web site:

<location path="Default Web Site/YourApp">
    <system.web>
        <!-- Settings for the Web site go here -->
    </system.web>
</location>

When you develop the ASP.NET code, you typically test it on a development machine with its own copies of machine.config and site web.config files. When you deploy the application on a production box, especially in an ISP scenario, you might not be able to restore the same settings. One possible reason is that the administrator does not want you to modify the current settings because they work well for all other applications or because of security concerns.

You can work around the issue by simply replicating any needed global settings into the application’s root web.config. If you are deploying your code to a service provider, you might find that many configuration elements have been locked down and cannot be overridden. (I’ll say more about this aspect in a moment.) In this case, a new application-specific <location> section created in machine.config or the site’s web.config can contain all the machine settings needed for your application without breaking others.

Whenever possible, though, you should try to replicate needed changes into the application’s web.config. This should always be the first option considered because it makes the entire application self-contained.

Unmodifiable Settings

The second <location> attribute you can specify—allowOverride—allows you to lock some settings at either the machine or application level. By grouping settings in a <location> element with the allowOverride attribute set to false, you tell the ASP.NET configuration system to raise an exception whenever a protected setting is overridden in a lower-level configuration file.

<location path="Default Web Site/YourApp" allowOverride="false">
    <system.web>
        <!-- These settings cannot be overridden -->
    </system.web>
</location>

The ultimate goal of this feature is to enable administrators to control the settings of a server that provides ASP.NET hosting. When a new application is installed in production, changes might be required on the target machine to reflect the native environment of the application. Updating the machine.config file on the production machine is not an issue as long as yours is the only application running or if you can directly control and configure all the applications hosted on that machine. However, in an application-hosting scenario, the administrator might decide to lock some machine settings to prevent installed applications from modifying them. In this way, the administrator can preserve, to the extent possible, the integrity of the hosting environment and guarantee that all applications run under the same conditions.

Note

By default, nearly all predefined sections can appear within a <location> section. In general, sections can be disallowed from appearing in <location> by using the allowLocation attribute. The allowLocation attribute of the <section> element determines the section’s capability of being customized for a particular path. Set it to false, and the section is not allowed to be used within a <location> section.

The <system.web> Section

The <system.web> section contains all the configuration elements that set up the ASP.NET runtime environment and controls how ASP.NET applications behave. Table 3-3 lists the entire sequence of first-level elements and their override level.

Table 3-3. The Full List of Important Sections Allowed Within <system.web>

Section

Overridable

Description

<anonymousIdentification>

Machine, application

Configures identification for users that are not authenticated.

<authentication>

Machine, application

Sets the authentication mechanism.

<authorization>

Everywhere

Indicates authorized users.

<browserCaps>

Everywhere

Lists known browser capabilities.

<clientTarget>

Everywhere

Lists predefined client targets.

<compilation>

Everywhere

Settings for batch compilation.

<customErrors>

Machine, application

Settings for custom error pages.

<deployment>

Machine only

Indicates how the application is deployed.

<deviceFilters>

Everywhere

Lists known mobile device capabilities.

<fullTrustAssemblies>

Machine, application

Lists full-trust assemblies for the application.

<globalization>

Everywhere

Settings for application localization.

<healthMonitoring>

Machine, application

Settings to monitor the status of the application.

<hostingEnvironment>

Machine, application

Defines configuration settings that control the behavior of the application hosting environment.

<httpCookies>

Everywhere

Configures properties for cookies used by an ASP.NET application.

<httpHandlers>

Everywhere

Lists registered HTTP handlers.

<httpModules>

Everywhere

Lists registered HTTP modules.

<httpRuntime>

Everywhere

Lists HTTP runtime settings.

<identity>

Everywhere

Sets impersonation.

<machineKey>

Machine, application

Encryption key for sensitive data.

<mobileControls>

Everywhere

Configures the behavior of mobile controls. In ASP.NET 4.0, mobile controls are deprecated.

<membership>

Machine, application

Defines settings for user authentication via ASP.NET membership.

<pages>

Everywhere

Controls features of ASP.NET pages.

<partialTrustVisibleAssemblies>

Machine, application

Lists partial-trust visible assemblies for the application

<processModel>

MachineOnly

Configures the process model.

<profile>

Machine, application

Defines settings for user profile’s data model.

<roleManager>

Machine, application

Defines settings for role management.

<securityPolicy>

Machine, application

Defines allowed trust levels.

<sessionPageState>

Everywhere

Defines page view-state settings for mobile controls.

<sessionState>

Machine, application

Configures the Session object.

<siteMap>

Machine, application

Defines settings used to support the navigation infrastructure.

<trace>

Everywhere

Configures the tracing system.

<trust>

Machine, application

Defines the default trust level.

<urlMappings>

Machine, application

Defines routes mapping a requested URL to a real page.

<webControls>

Everywhere

Locates client scripts.

<webParts>

Everywhere

Managed Web Parts.

<webServices>

Everywhere

Configures Web services. The Web Services technology is considered obsolete, as is this section.

<xhtmlConformance>

Everywhere

Defines settings for XHTML conformance.

Each of the elements listed in Table 3-3 features its own schema and provides attributes and enumerations to pick values from.

In addition to the sections listed in Table 3-3, the <system.web> group contains a subgroup named <Caching>. Table 3-4 lists the child elements.

Table 3-4. Sections Allowed Within <Caching>

Section

Overridable

Description

<cache>

Machine, application

Configures the global cache settings for an ASP.NET application.

<outputCache>

Machine, application

Configures the output cache for a Web application.

<outputCacheSettings>

Machine, application

Defines caching profiles.

<sqlCacheDependency>

Machine, application

Configures the SQL cache dependencies for an ASP.NET application.

Let’s examine some of the aforementioned sections in a bit more detail. For a complete reference, though, you might want to check out the excellent MSDN online documentation starting at http://msdn.microsoft.com/en-us/library/b5ysx397.aspx.

The <anonymousIdentification> Section

Anonymous identification is a feature that assigns a predefined identity to users who connect anonymously to an application. Anonymous identification has nothing to do with the anonymous user you can set at the IIS level, nor does it affect the authentication mechanism of ASP.NET. The feature is designed to work with the user profile API to simplify the way you write code in scenarios where both authenticated and unauthenticated users can use the site.

The <anonymousIdentification> section allows you to configure how it works. Here’s the overall schema of the section:

<anonymousIdentification
   enabled="[true | false]"
   cookieless="[UseUri | UseCookies | AutoDetect | UseDeviceProfile]"
   cookieName=""
   cookiePath=""
   cookieProtection="[None | Validation | Encryption | All]"
   cookieRequireSSL="[true | false]"
   cookieSlidingExpiration="[true | false]"
   cookieTimeout="[DD.HH:MM:SS]"
   domain="cookie domain"
/>

Basically, anonymous identification creates a cookied or cookieless ticket and associates it with the ongoing request. The enabled attribute turns the feature on and off; the cookieless attribute instructs the ASP.NET runtime about cookie usage. Table 3-5 illustrates the options for the cookieless attribute.

Table 3-5. Options for the cookieless Attribute

Value

Description

AutoDetect

Uses cookies if the browser has cookie support currently enabled. It uses the cookieless mechanism otherwise.

UseCookie

Always uses cookies, regardless of the browser capabilities.

UseDeviceProfile

Uses cookies if the browser supports them, and uses the cookieless mechanism otherwise. When this option is used, no attempt is made to check whether cookie support is really enabled for the requesting device. This is the default option.

UseUri

Never uses cookies, regardless of the browser capabilities.

All other attributes relate to the cookie, if one gets created. You can set its name—the default name is .ASPXANONYMOUS—as well as its path, domain, protection, expiration, and timeout. You can also indicate whether Secure Sockets Layer (SSL) should be used to transmit the cookie.

The <authentication> Section

The <authentication> section allows you to configure a Web site for various types of user authentication, including Forms authentication as well as Passport and IIS-driven authentication. This section has two mutually exclusive subsections—<forms> and <passport>—and the mode attribute to control the authentication mode requested by an application. Allowable values for the mode attribute are shown in Table 3-6.

Table 3-6. Supported Authentication Modes

Value

Description

Forms

Makes use of a custom form to collect logon information.

Passport

Exploits the authentication services of Microsoft Passport (now LiveID). In ASP.NET 4, classes dealing with Passport authentication are marked obsolete.

None

Indicates ASP.NET should not enforce any type of authentication, which means only anonymous users can connect or the application itself provides a built-in mechanism.

Windows

Exploits any authentication services of IIS—basic, digest, NTLMKerberos, or certificates. This is the default mode.

When using Forms authentication, you are allowed to specify a few additional parameters, such as name, loginURL, protection, and cookieless. Table 3-7 lists the attributes of the <forms> element.

Table 3-7. Attributes of the <forms> Element

Attribute

Description

cookieless

Defines whether and how cookies are used for authentication tickets. Feasible values are the same as those listed in Table 3-5.

defaultUrl

Defines the URL to redirect after authentication. The default is default.aspx.

domain

Specifies a domain name to be set on outgoing authentication cookies.

enableCrossAppRedirects

Indicates whether users can be authenticated by external applications when authentication is cookieless. The setting is ignored if cookies are enabled. When cookies are enabled, cross-application authentication is always possible.

loginUrl

Specifies the URL to which the request is redirected for login if no valid authentication cookie is found.

name

Specifies the name of the HTTP cookie to use for authentication. The default name is .ASPXAUTH.

path

Specifies the path for the authentication cookies issued by the application. The default value is a slash (/). Note that some browsers are case-sensitive and will not send cookies back if there is a path case mismatch.

protection

Indicates how the application intends to protect the authentication cookie. Feasible values are All, Encryption, Validation, and None. The default is All.

requireSSL

Indicates whether an SSL connection is required to transmit the authentication cookie. The default is false. If true, ASP.NET sets the Secure property on the authentication cookie object so that a compliant browser does not return the cookie unless the connection is using SSL.

slidingExpiration

Indicates whether sliding expiration is enabled. The default is false, meaning that the cookie expires at a set interval from the time it was originally issued. The interval is determined by the timeout attribute.

timeout

Specifies the amount of time, in minutes, after which the authentication cookie expires. The default value is 30.

Note that the description of cookie-related attributes in Table 3-7 works also for similar attributes in the <anonymousIdentification> section.

I’ll return to authentication and security in Chapter 19. In particular, in that chapter you’ll discover various flavors of Forms authentication that, although described as custom types of Forms authentication, are gaining wide acceptance in real-world applications. Two examples are OpenID and claims-based Windows Identity Foundation (WIF).

Overall, when it comes to providing authentication for an ASP.NET application, the primary choice is Forms authentication, including when it’s in the form of OpenID implementations such as dotnetOpenAuth. Windows authentication and Passport are seldom used today even though both, especially Windows authentication, still serve the needs of a particular segment of applications. An emerging approach is based on Windows Identity Foundation (WIF). With a WIF integrated with Web Forms, the user navigates to inside the application and then, when authentication is required, the user is redirected to the configured Security Token Service (STS), logs in there, and is then redirected back to the application with his own set of claims. (I’ll return to WIF in Chapter 19.)

The <authorization> Section

The <authorization> section is used to define a declarative filter to control access to the resources of the application. The <authorization> section contains two subsections, named <allow> and <deny>, that can be used to allow and deny access to users. Both elements feature three attributes—users, roles, and verbs—filled with a comma-separated list of names, as the following code demonstrates:

<authorization>
    <allow users="comma-separated list of users"
            roles="comma-separated list of roles"
            verbs="comma-separated list of verbs" />
    <deny users="comma-separated list of users"
           roles="comma-separated list of roles"
           verbs="comma-separated list of verbs" />
</authorization>

The <allow> element authorizes access to any user whose name appears in the list—that is, to all users with any of the specified roles. Authorized users can execute only the HTTP verbs (for example, POST and GET) indicated by the verbs attribute.

Conversely, the <deny> element prohibits listed users from executing the specified actions. The default setting allows all users free access to the resources of the application. When specifying the user name, a couple of shortcuts are allowed. The asterisk (*) means “all users,” whereas the question mark (?) stands for the “anonymous user.”

Important

The <authorization> section is all about declarative authorization. It uses a fixed syntax to feed authorization modules (UrlAuthorization and FileAuthorizationModule) and have them block unauthorized users as they try to access a URL or a file. Most applications, instead, prefer to incorporate authorization within their business layer in a fluent way. In doing so, applications associate users with roles and check roles before proceeding with any critical operations. For this approach, you don’t need the <authorization> section. The section, however, remains quite useful for relatively simple scenarios when you just want to limit access to a specific subset of users or protect the entire content of pages in a given area of the application. (See Chapter 19.)

The <browserCaps> Section

The <browserCaps> section enumerates the characteristics and capabilities of the supported browsers, including mobile devices. The <browserCaps> section is tightly coupled with the HttpBrowserCapabilities class and MobileCapabilities, which allows the ASP.NET runtime to gather technical information about the browser that is running on the client.

So ASP.NET supports the concept of browser capabilities and gives you a chance to check them and build your applications accordingly. You use any browser information available through the Browser property of the intrinsic Request object. The point is, where would ASP.NET find information to feed the Browser property?

Internally, the Request object first looks at the user-agent information that comes with the HTTP request and then matches this information to some sort of provider. The internal structure of the browser provider has evolved quite significantly lately and especially in ASP.NET 4.

In the beginning, the <browserCaps> section was the only repository for browser information. Under the <browserCaps> section, you find a number of commercial browsers described in terms of their run-time capabilities, such as cookies, tables and frames support, accepted script languages, XML DOM, and operating system. The element can be declared at any level in the application, thus making it possible for you to enable certain levels of browser support for certain applications. The list of available browsers can be updated as required to detect future browsers and browser capabilities. The use of the <browserCaps> element to define browsers was deprecated already in ASP.NET 2.0. It is, however, fully supported still today.

An alternate approach to using <browserCaps> is reading browser information from matching files with a .browser extension located in the folder Microsoft.NETframework[version]configrowsers. Figure 3-2 shows the default content of the folder for a site equipped with ASP.NET 4.

The list of .browser files in ASP.NET 4.

Figure 3-2. The list of .browser files in ASP.NET 4.

In ASP.NET 4, yet another approach is supported to provide browser capabilities—browser providers. In a nutshell, a browser provider is a class you register with the application using the classic provider model, as shown in the following code snippet, or using a line of code in global.asax:

<system.web>
  <browserCaps provider="Samples.CustomProvider, Samples" />
</system.web>

The browser provider usually derives from the system-provided base class HttpCapabilitiesProvider and extends it by overriding some methods.

The <caching> Section

The <caching> section configures the cache settings for an ASP.NET application. It consists of four child sections: cache, outputCache, outputCacheSettings, and sqlCacheDependency.

The <cache> section defines a few application-wide settings that relate to caching. For example, the percentagePhysicalMemoryUsedLimit and privateBytesLimit attributes indicate the maximum size of memory (percentage and bytes) that can be occupied before the cache starts flushing expired items and attempting to reclaim memory. Here’s the schema of the section with default values:

<cache disableMemoryCollection = "false"
    disableExpiration = "false"
    privateBytesLimit = "0"
    percentagePhysicalMemoryUsedLimit = "89"
    privateBytesPollTime = "00:02:00" />

The default time interval between polling for the memory usage is 2 minutes. Note that by setting the disableExpiration attribute you can disable the automatic scavenging of expired cache items—the most defining trait of ASP.NET cache.

The <outputCache> section takes care of output caching. Here is the schema of the section with default values:

<outputCache defaultProvider="AspNetInternalProvider"
    enableOutputCache = "true"
    enableKernelCacheForVaryByStar = "false"
    enableFragmentCache = "true"
    sendCacheControlHeader = "true"
    omitVaryStar = "false">
</outputCache>

If output or fragment caching is disabled in the configuration file, no pages or user controls are cached regardless of the programmatic settings. The sendCacheControlHeader attribute indicates whether the cache-control:private header is sent by the output cache module by default. Similarly, the omitVaryStar attribute enables or disables sending an HTTP Vary: * header in the response. The enableKernelCacheForVaryByStar attribute controls whether kernel caching is enabled or not. You should note that kernel caching is supported only for compressed responses. This means that regardless of the attribute’s value, kernel caching won’t work any time the client requests an uncompressed response.

The defaultProvider attribute indicates the component that takes care of storing and serving the cached output. The default provider is based on the same code that powered output caching in earlier versions of ASP.NET. The store is the in-memory cache. By writing your own provider, you can change the storage of the output cache. Note that the AspNetInternalProvider provider name doesn’t really match any class in the system.web assembly. It is simply a moniker that instructs the system to go with the built-in logic that worked for any previous versions of ASP.NET. The framework offers a new abstract class—OutputCacheProvider—that represents your starting point on the way to building custom output cache providers.

The <outputCacheSettings> section contains groups of cache settings that can be applied to pages through the @OutputCache directive. The section contains only one child section, named <outputCacheProfiles>. An output cache profile is simply a way of referencing multiple settings with a single name. Here’s an example:

<outputCacheSettings>
  <outputCacheProfiles>
    <add name="ServerOnly"
      duration="60"
      varyByCustom="browser" />
  </outputCacheProfiles>
</outputCacheSettings>

In the example, the ServerOnly profile defines a cache duration of 60 seconds and stores different versions of the page based on browser type. Here is the schema of <outputCacheProfiles>:

<outputCacheProfiles>
   <add name = ""
      enabled = "true"
      duration = "-1"
      location = ""
      sqlDependency = ""
      varyByCustom = ""
      varyByControl = ""
      varyByHeader = ""
      varyByParam = ""
      noStore = "false"/>
</outputCacheProfiles>

A database dependency is a special case of custom dependency that consists of the automatic invalidation of some cached data when the contents of the source database table changes. In ASP.NET, this feature is implemented through the SqlCacheDependency class. The <sqlCacheDependency> section defines the settings used by the SqlCacheDependency class when using database caching and table-based polling against versions of Microsoft SQL Server equal or newer than version 7.

<sqlCacheDependency enabled="true" pollTime="1000">
   <databases>
      <add name="Northwind" connectionStringName="LocalNWind" />
   </databases>
</sqlCacheDependency>

The pollTime attribute indicates (in milliseconds) the interval of the polling. In the preceding sample, any monitored table will be checked every second. Under the <databases> node, you find a reference to monitored databases. The name attribute is used only to name the dependency. The connectionStringName attribute points to an entry in the <connectionStrings> section of the web.config file and denotes the connection string to access the database. Which tables in the listed databases will really be monitored depends on the effects produced by another tool—aspnet_regsql.exe. I’ll return to this form of caching in Chapter 18,

Any values stored in the <sqlCacheDependency> section have no effect when using SqlCacheDependency in conjunction with query notifications on SQL Server 2005 and newer versions.

The <customErrors> Section

The <customErrors> section specifies the error-handling policy for an ASP.NET application. By default, when an error occurs on a page, the local host sees the detailed ASP.NET error page, while remote clients are shown a custom error page or a generic page if no custom page is specified. This policy is controlled through the Mode attribute.

The Mode attribute can be set to On, Off, or RemoteOnly, which is the default. If it’s set to On, custom error pages are displayed both locally and remotely; if it’s set to Off, no special error-handling mechanism is active and all users receive the typical ASP.NET (yellow) error page with the original runtime’s or compiler’s error message and the stack trace.

Custom error pages can be specified in two ways. You can provide a generic error page as well as error-specific pages. A custom error page that is not error-specific can be set through the defaultRedirect attribute of the <customErrors> element. This setting is ignored if the mode is Off.

<customErrors defaultRedirect="Errors/appGenericError.aspx" mode="On">
    <error statusCode="404" redirect="Errors/notfound.aspx" />
    <error statusCode="500" redirect="Errors/internal.aspx" />
</customErrors>

The <customErrors> section supports a repeatable child <error> tag that is used to associate a custom page with a particular error code. You should note that only certain status codes are supported. Some error codes, such as 403, might come directly from IIS and never get to ASP.NET.

The <error> tag has two optional attributes, redirect and statusCode. The redirect attribute points to the URL of the page, whereas the statusCode specifies the HTTP status code that will result in an error. If the custom mode is enabled, but no error-specific page is known, the default redirect is used. If the custom mode is enabled, but no custom page is specified, the ASP.NET generic error page is used.

Important

The aforementioned ASP.NET vulnerability discovered in September 2010 brought about a best practice as far ASP.NET security is concerned. You are now discouraged from using any <error> element to return an error-specific page. By examining the error code, in fact, the attacker could learn enough to compromise your system. The recommended approach is setting the Mode attribute to On and to have all errors handled by the same error page, which is set through the defaultRedirect attribute. The content of the default error page is not relevant; what matters is that you don’t provide means to potential attackers to distinguish between types of responses.

The <deployment> Section

The <deployment> section indicates the deployment mode of the application and has only one Boolean attribute, named retail. The attribute indicates whether the application is intended to be deployed for production (retail equals true) or test (retail equals false).

<deployment retail="true" />

When retail is set to true, ASP.NET automatically disables certain configuration settings, such as trace output, custom errors, and debug capabilities. When the default value of retail is false, each application is automatically deployed for testing.

The <globalization> Section

The <globalization> section configures the globalization settings of ASP.NET applications so that requests and responses take into account encoding and culture information. The attributes of the <globalization> section are shown in Table 3-8.

Table 3-8. Globalization Attributes

Attribute

Description

culture

Specifies the culture to be used to process requests.

fileEncoding

Specifies the encoding for ASP.NET resource files (.aspx, .asmx, and .asax). Unicode and UTF-8 files saved with the byte order mark prefix are recognized regardless of the value of the attribute.

requestEncoding

Specifies the assumed encoding of each request, including posted data and the query string. The default is UTF-8.

responseEncoding

Specifies the content encoding of responses. The default is UTF-8.

uiCulture

Specifies the culture name to be used to look up locale-dependent resources at run time.

Note that, if specified, the Accept-Charset attribute in the request overrides the default requestEncoding setting. If you remove any encoding setting from the configuration files, ASP.NET defaults to the server’s locale. In the majority of cases, requestEncoding and responseEncoding have the same value.

Valid names for the culture and uiCulture attributes are non-neutral culture names such as en-US, en-AU, and it-IT. A culture name is made of two elements—the language and country/region—and both are to be specified in this context.

The <httpHandlers> Section

The section allows you to register application-specific HTTP handlers that take care of ad hoc URLs invoked over given HTTP verbs. I’ll dissect the syntax and usage of the <httpHandlers> section in the next chapter.

The <httpModules> Section

The <httpModules> section allows you to register application-specific HTTP modules that take care of hooking up specific stages during the processing of an ASP.NET request. I’ll dissect the syntax and usage of the <httpModules> section in the next chapter.

The <healthMonitoring> Section

Health monitoring is a system feature that allows the production staff to monitor the status of a deployed application and track significant events related to performance, failures, and anomalies. The ASP.NET health monitoring system works by firing events to providers. The event contains actual information about what happened; the provider processes the information. Here is the overall schema:

<healthMonitoring
   enabled="true|false"
   heartbeatInterval="HH:MM:SS">
   <bufferModes>...</bufferModes>
   <providers>...</providers>
   <eventMappings>...</eventMappings>
   <profiles>...</profiles>
   <rules>...</rules>
</healthMonitoring>

The enabled attribute specifies whether health monitoring is enabled. It is true by default. The heartbeatInterval attribute indicates how often the heartbeat event is raised. The heartbeat event serves as a timer for the whole subsystem and is raised at regular intervals to capture useful runtime state information. The heartbeat is just one of the events that the health monitoring system can detect. Other events track unhandled exceptions, request processing, application lifetime, and the success and failure audits. Child sections, listed in Table 3-9, let you configure the whole subsystem.

Table 3-9. Elements for Health Monitoring

Element

Description

bufferModes

Used with Microsoft SQL Server and Web event providers (with built-in e-mail capability) to determine how often to flush the various events to the provider and the size of the intermediate buffer.

eventMappings

Maps friendly event names to the event classes. You use this element to register custom event types.

profiles

Defines parameter sets to use when configuring events.

providers

Defines the health monitoring providers that process events. Predefined providers write to a SQL Server table and the Event Log, and they send e-mail. You use this element to register custom Web event providers.

rules

Maps events to providers.

The interval for the heartbeat event is set to 0 by default, meaning that no heartbeat event is raised by default.

The <hostingEnvironment> Section

The <hostingEnvironment> section defines configuration settings that control the behavior of the application-hosting environment. As you can see in the following code segment, the section has three attributes: idleTimeout, shadowCopyBinAssemblies, and shutdownTimeout:

<hostingEnvironment idleTimeout="HH:MM:SS"
                    shadowCopyBinAssemblies="true|false"
                    shutdownTimeout="number"
                    urlMetadataSlidingExpiration="HH:MM:SS" />

The idleTimeout attribute sets the amount of time to wait before unloading an inactive application. It is set to Infinite by default, meaning that inactive applications are not automatically unloaded. Note also that “inactive” doesn’t mean nonresponsive; an application is inactive if no user is working with it, and this is normally not by itself a good reason to kill it. The shadowCopyBinAssemblies attribute indicates whether the assemblies of an application in the Bin directory are shadow-copied to the application’s ASP.NET temporary files directory. It is true by default. Finally, the shutdownTimeout attribute sets the number of seconds (30 by default) it should take to shut down the application. Finally, the urlMetadataSlidingExpiration attribute indicates for how long the URL metadata will be cached by ASP.NET. The default is 1 minute. Both idleTimeout and urlMetadataSlidingExpiration attributes can be set to any time span, ranging from seconds to minutes and hours.

Note

Shadow-copy is a feature of the .NET Framework that ASP.NET uses extensively. When shadow-copy is enabled on an AppDomain, assemblies loaded in that AppDomain will be copied to an internal cache directory and used from there. In this way, the original file is not locked and can be changed at will. In ASP.NET, you can control the feature through the shadowCopyBinAssemblies attribute.

The <httpCookies> Section

The <httpCookies> section is used to configure properties for cookies used by ASP.NET applications. Here is the overall schema:

<httpCookies domain="string"
             httpOnlyCookies="true|false"
             requireSSL="true|false" />

The domain attribute indicates the default Internet domain of the cookie and is set to the empty string by default. The requireSSL attribute is false by default. If it’s true, SSL is required for all cookies. The httpOnlyCookies attribute enables ASP.NET to output an extra HttpOnly cookie attribute that can help mitigate cross-site scripting threats that result in stolen cookies. When a cookie that has the HttpOnly attribute set to true is received by a compliant browser such as Internet Explorer 6 SP1 (and superior), it is inaccessible to client-side script. Adding the HttpOnly attribute is as easy as appending the HttpOnly string to the path of all response cookies.

Caution

The HttpOnly attribute is helpful when it comes to raising the security bar, but it is not a silver bullet. Any network monitoring tool, in fact, can easily detect it, thus giving malicious users an important bit of help.

Finally, note that any settings defined in the <httpCookies> section can be overridden by classes that actually create cookies in ASP.NET pages.

The <httpRuntime> Section

The <httpRuntime> section configures some run-time parameters for the ASP.NET pipeline. Interestingly enough, the section can be declared at any level, including subdirectory levels. This fact accounts for the great flexibility that allows you to set up the run-time environment with the finest granularity. Configurable attributes are listed in Table 3-10.

Table 3-10. ASP.NET Runtime Attributes

Attribute

Description

apartmentThreading

Enables apartment threading for classic ASP compatibility. The default is false.

appRequestQueueLimit

Specifies the maximum number of requests the application is allowed to queue before returning error 503—Server too busy. The default is 5000.

delayNotificationTimeout

Specifies the timeout for delaying notifications. The default is 5 seconds.

Enable

Specifies whether the AppDomain is enabled to accept incoming requests. This is true by default.

enableHeaderChecking

Specifies whether ASP.NET should check the request header for potential injection attacks. If an attack is detected, ASP.NET responds with an error. This is true by default.

enableKernelOutputCache

Enables the http.sys kernel-level cache on IIS 6 and higher. The default is true.

enableVersionHeader

Outputs a header with the ASP.NET version with each request. The default is true. You can disable it for production sites.

encoderType

Indicates the class to be used for any encoding and decoding tasks in ASP.NET, such as those performed by HttpServerUtility.

executionTimeout

Specifies the maximum number of seconds a request is allowed to execute before ASP.NET automatically times it out. The default is 110 seconds.

maxQueryStringLength

Indicates the maximum accepted size of the query string. The default is 260.

maxRequestLength

Indicates the maximum accepted size (in KB) of a Web request. No request is accepted if its overall length exceeds the threshold of 4 MB.

maxUrlLength

Indicates the maximum accepted size of the URL. The default is 260.

minLocalRequestFreeThreads

Indicates the minimum number of free threads needed to allow the execution of new local requests. The default threshold value is set to 4.

minFreeThreads

Indicates the minimum number of free threads needed to allow the execution of new Web requests. The default threshold value is set to 8.

requestLengthDiskThreshold

Specifies the input stream buffering threshold limit in number of bytes. Its value should not exceed the maxRequestLength. The default is 256 bytes.

requireRootedSaveAsPath

Specifies whether the file name parameter in a Request’s SaveAs method must be an absolute path.

requestValidationMode

Indicates whether HTTP request validation can be customized (only in ASP.NET 4) or whether it should happen through a system-provided layer (as in earlier versions). The default value is “4.0”. Anything else is considered as “do as ASP.NET 2.0 does.”

requestValidationType

Indicates the name of a type that is used to validate HTTP requests.

sendCacheControlHeader

Specifies whether to send a cache control header.

shutDownTimeout

Number of seconds that are allowed for the worker process to shut down. When the timeout expires, ASP.NET shuts down the worker process. The default is 90 seconds.

useFullyQualifiedRedirectUrl

Indicates whether client redirects must be automatically converted to fully qualified URLs (true) or used as specified in the page source code (false). The default is false.

waitChangeNotification, maxWaitChangeNotification

Indicates the minimum and maximum number of seconds to wait (0 by default) before restarting the AppDomain after a file change notification. This is actually pretty important for XCopy deployment, especially with named assemblies in precompiled sites.

Notice that ASP.NET won’t process a request if not enough free threads are available in the thread pool. When this happens, the request is queued to the application until the threshold set by the appRequestQueueLimit is exceeded. But why, in the default case, does ASP.NET need at least eight free threads to execute a request? These free threads are at the disposal of ongoing requests (for example, the request for a download of linked images, style sheets, or user controls) if they issue child requests to complete processing.

Another small number of threads (four by default) is kept reserved for child requests coming through the local host. If the request has been generated locally—that is, the client IP is 127.0.0.1 or matches the server IP—it is scheduled on one of the threads in the pool reserved for local calls. Often local requests originate as child requests—for example, when an ASP.NET page invokes a Web service on the same server. There’s no need in this case to consume two threads from the pool to serve two related requests, one of which is waiting for the other to terminate. By using an additional thread pool, you actually assign local requests a slightly higher priority and reduce the risk of deadlocks.

The <identity> Section

The <identity> section controls the identity of the ASP.NET application. It supports three attributes: impersonate, userName, and password. The key attribute is impersonate. It is set to false by default, which means that the application does not impersonate any client user.

<identity impersonate="true" />

When impersonate is set to true, each request is served by ASP.NET impersonating either the Windows user currently logged on or the user specified through the userName and password attributes.

Note that user name and password are stored in clear text in the configuration file. Although IIS never serves requests for configuration files, a web.config file can be read by other means. You should consider forms of protection for the contents of the section. In ASP.NET, you can encrypt the <identity> section using XML Encryption.

The <machineKey> Section

Valid at the machine and application levels, the <machineKey> section configures the keys to encrypt and decrypt forms authentication tickets and view-state data. Here’s the schema:

<machineKey
  validationKey="AutoGenerate,IsolateApps"
  decryptionKey="AutoGenerate,IsolateApps"
  validation="HMACSHA256"
  decryption="Auto" />

The validationKey and decryptionKey attributes are strings and specify the encryption and decryption keys, respectively. An encryption key is a sequence of characters whose length ranges from a minimum of 40 characters to a maximum of 128.

The validation attribute, on the other hand, indicates the type of encryption used to validate data. Allowable values are SHA1, MD5, 3DES, AES, HMACSHA256 (the default), HMACSHA384, and HMACSHA512.

Finally, the decryption attribute indicates the type of hashing algorithm that is used for decrypting data. Feasible values are DES, AES, and 3DES. The default is Auto, meaning that ASP.NET determines which decryption algorithm to use based on the configuration default settings.

The default value of both the validationKey and decryptionKey attributes is AutoGenerate,IsolateApps. This means that keys are autogenerated at setup time and stored in the Local Security Authority (LSA). LSA is a protected subsystem of Windows NT–based operating systems that maintains information about all aspects of local security on a system. The IsolateApps modifier instructs ASP.NET to generate a key that is unique for each application.

Settings in the <machineKey> section are a critical element of applications hosted on multiple machines, such as in a Web farm or a failover cluster. All machines across a network must share the same <machineKey> settings. For this reason, you might want to set validationKey and decryptionKey attributes manually to ensure consistent configuration in a multiserver environment.

The <membership> Section

The <membership> section defines parameters for managing and authenticating user accounts through the ASP.NET membership API. Here’s the schema of the section:

<membership
    defaultProvider="provider name"
    userIsOnlineTimeWindow="number of minutes"
    hashAlgorithmType="SHA1">
    <providers>
      ...
    </providers>
</membership>

The defaultProvider attribute indicates the name of the default membership provider—it is SqlMembershipProvider by default. The attribute named userIsOnlineTimeWindow specifies how long a user can be idle and still be considered online. The interval is set to 15 minutes by default. The hashAlgorithmType refers to the name of the encryption algorithm that is used to hash password values. (The default is SHA1.)

The <providers> child section lists all registered membership providers. Here’s the schema:

<membership>
   <providers>
     <add name="MyProvider"
          type="Samples.MyMembershipProvider"
          connectionStringName="MyConnString"
          enablePasswordRetrieval="false"
          enablePasswordReset="true"
          requiresQuestionAndAnswer="true"
          passwordFormat="Hashed" />
      ...
   </providers>
</membership>

You use the <providers> section to add custom membership providers. Each provider has its own set of attributes, as shown in the upcoming sections.

The <pages> Section

The <pages> section sets default values for many of the @Page directive attributes and declaratively configures the run-time environment for a Web page. Table 3-11 enumerates the supported attributes.

Table 3-11. Attributes to Configure ASP.NET Pages

Attribute

Description

asyncTimeout

Number of seconds to wait for an asynchronous handler to complete during asynchronous processing. The default is 45 seconds.

autoEventWireup

Indicates whether page events are automatically assigned to event handlers with a particular name (for example, Page_Load). It’s set to true by default.

buffer

Indicates whether or not response buffering is enabled. It’s set to true by default.

clientIDMode

Specifies the algorithm to use to generate the client ID for server controls. Feasible values are AutoID, Static, Predictable, and Inherit.

compilationMode

Indicates whether an ASP.NET page or control should be compiled at run time. Allowable values are Never, Auto, and Always—the default. Auto means that ASP.NET will not compile the page, if possible.

controlRenderingCompatibilityVersion

Indicates how controls are expected to render out their markup. The default value is 4.0, meaning that the markup is updated to the latest version. By setting it to 3.5 (no other values are supported), you fall back to the behavior of earlier versions of ASP.NET.

enableEventValidation

Specifies whether pages and controls validate postback and callback events. The default is true.

enableSessionState

Indicates whether session state is enabled. It’s set to true by default; it also accepts as values false and ReadOnly. The session state is disabled altogether if the attribute is set to false; it is accessible only for reading if set to ReadOnly.

enableViewState

Specifies whether view state is enabled. It’s set to true by default.

enableViewStateMac

Specifies whether the view state of a page should be checked for tampering on each page postback. It’s set to true by default.

maintainScrollPositionOnPostBack

If this is set to true, the page maintains the same scroll position after a postback.

masterPageFile

Specifies the master page for the pages in the scope of the configuration file.

maxPageStateFieldLength

Indicates the maximum length of the view-state field. A negative value indicates that no upper limit exists. If the size of the view state exceeds the maximum, the contents will be sent in chunks.

pageBaseType

Indicates the base code-behind class that .aspx pages inherit by default—unless a code-behind class is explicitly provided. The default class is System.Web.UI.Page. The new class name must include assembly information.

pageParserFilterType

Specifies the type of filter class that is used by the ASP.NET parser to determine whether an item is allowed in the page at parse time.

smartNavigation

Specifies whether smart navigation is enabled. This is set to false by default. It’s deprecated in favor of the maintainScrollPositionOnPostBack attribute.

styleSheetTheme

Name of the style-sheet theme used for the pages in the scope of the configuration file.

theme

Name of the theme used for the pages in the scope of the configuration file.

userControlBaseType

Indicates the code-behind class that .ascx user controls inherit by default. The default class is System.Web.UI.UserControl. The new class name must include assembly information.

validateRequest

Indicates that ASP.NET examines all input from the browser for potentially dangerous data. It’s set to true by default.

viewStateEncryptionMode

Indicates the encryption mode of the view state. Feasible values are Always, Never, or Auto. Auto means that the view state is encrypted only if a control requests it.

In particular, the pageBaseType attribute is an extremely powerful setting you might want to leverage when all your application pages inherit from a common code-behind class. In this case, instead of modifying all the pages, you centralize the setting in the web.config file at the level (machine, application, or subdirectory) you want.

An interesting attribute is maxPageStateFieldLength. One of the problems developers might experience with a too-large view state is that some legacy firewalls and proxy servers might not be capable of carrying all those bytes back and forth for a single input field. As a result, the content of the view state is truncated and the application fails. This is particularly likely to happen on pretty simple Web browsers, such as those you find in palmtops and smartphones. If the real size of the view state exceeds the upper limit set through the maxPageStateFieldLength attribute, ASP.NET automatically cuts the view state into chunks and sends it down using multiple hidden fields. For example, if you set maxPageStateFieldLength to 5, here’s what the page contains:

<input type="hidden" id="__VIEWSTATEFIELDCOUNT" value="..." />
<input type="hidden" id="__VIEWSTATE" value="/wEPD" />
<input type="hidden" id="__VIEWSTATE1" value="wUKLT" />
<input type="hidden" id="__VIEWSTATE2" value="I2MjI" />
...

The final byte count of the client page is even a bit higher than in the default case, but at least your page won’t fail because of a truncated view state on simple and not too powerful Web browsers.

A sign of the evolution of the Web platform is the clientIDMode attribute introduced in ASP.NET 4. Earlier versions of ASP.NET use a built-in algorithm to generate the client ID values for HTML elements output by server controls. The algorithm guarantees uniqueness but do not necessarily result in predictable IDs. Until the advent of AJAX, that has never been a problem. AJAX brought developers to write more client-side code and subsequently raised the need for accessing in a reliable and easy way any DOM element added by ASP.NET controls. The clientIDMode attribute offers two main options: using static IDs (and thus accepting the potential risk of having duplicates) and using predictable IDs. A predictable ID is essentially an ID generated by ASP.NET but through a much simpler algorithm that doesn’t walk through the entire list of naming containers like the default algorithm we used for years.

The <pages> section contains a bunch of child sections, as shown here:

<pages>
   <controls>...</controls>
   <namespaces>...</namespaces>
   <tagMapping>...</tagMapping>
   <ignoreDeviceFilters>...</ignoreDeviceFilters>
</pages>

The <controls> and <namespaces> sections define a collection of @Register and @Import directives to be implicitly added to any page. The <tagMapping> section, instead, plays the role of remapping an existing control type to another type specified in the markup:

<pages>
      <tagMapping>
         <add
            tagType=
               "System.Web.UI.WebControls.TextBox"
            mappedTagType=
               "Samples.MyTextBox" />
      </tagMapping>
</pages>

As an example, you can use this tag to automatically invoke a TextBox of yours wherever the source code invokes, instead, the standard TextBox control out of the <asp:TextBox> markup.

Finally, <ignoreDeviceFilters> defines a collection of elements that identify the device-specific content that ASP.NET should ignore when it displays a page. Device-specific content is listed through a <filter> child element. The usefulness of this feature is illustrated by the following example. Suppose you have the following markup in an ASP.NET page:

<asp:Text moz:Text="Hello Mozilla" ie:Text="Hello IE">

In this instance, moz and ie are device filters, meaning that the property they attribute should be used only if the user agent matches the filter. So where’s the problem? The problem arises with some AJAX functionality and microformats that extended the schema to allow additions. An example is when some JavaScript libraries add their own expando attributes prefixed with a string, as shown here:

<asp:Text sys:Text="Hello from Ajax">

Without countermeasures, the sys prefix would be mistaken for a device filter and the whole attribute would be stripped off in absence of a matching filter. In fact, sys is not likely to be the nickname of any browser.

<pages>
   <ignoreDeviceFilters>
     <filter add="sys" />
   </ignoreDeviceFilters>
</pages>

In ASP.NET 4, by adding the previous script to the configuration file you instruct ASP.NET to ignore some of the names that appear to be device filters.

The <processModel> Section

This section configures the ASP.NET process model—that is, the procedure that brings a request to be processed in the HTTP pipeline. The attributes of the <processModel> section are actually read by unmanaged code—the aspnet_isapi.dll ISAPI extension. For this reason, you need to restart IIS to have any changes applied. For the same reason, you can never override any attributes in the <processModel> section in a web.config file. The <processModel> section can exist only within a machine.config file, and it affects all ASP.NET applications that are running on the server. The following code snippet illustrates the schema of the section:

<processModel
   enable="true|false"
   timeout="hrs:mins:secs|Infinite"
   idleTimeout="hrs:mins:secs|Infinite"
   shutdownTimeout="hrs:mins:secs|Infinite"
   requestLimit="num|Infinite"
   requestQueueLimit="num|Infinite"
   restartQueueLimit="num|Infinite"
   memoryLimit="percent"
   webGarden="true|false"
   cpuMask="num"
   userName="username"
   password="password"
   logLevel="All|None|Errors"
   clientConnectedCheck="hrs:mins:secs|Infinite"
   comAuthenticationLevel="Default|None|Connect|Call|
               Pkt|PktIntegrity|PktPrivacy"
   comImpersonationLevel="Default|Anonymous|Identify|
               Impersonate|Delegate"
   responseDeadlockInterval="hrs:mins:secs|Infinite"
   responseRestartDeadlockInterval="hrs:mins:secs|Infinite"
   autoConfig="true|false"
   maxWorkerThreads="num"
   maxIoThreads="num"
   minWorkerThreads="num"
   minIoThreads="num"
   serverErrorMessageFile=""
   pingFrequency="Infinite"
   pingTimeout="Infinite"
   maxAppDomains="2000" />

As mentioned, the machine.config file remains the root of the configuration hierarchy also in IIS 7 and newer versions. The second level in the hierarchy is given by the root web.config file located in the same folder as machine.config.

Under IIS 7, or newer, an additional level in the hierarchy is represented by the applicationHost.config file located in the system32inetsrvconfig folder. To edit the content of this file, and thus configure most of the settings of the process model, you can use the visual editors in the IIS Manager tool. Figure 3-3 shows how to configure some parameters of the process model for a given application pool in the server.

Configure the process model for a given application pools in IIS 7.5.

Figure 3-3. Configure the process model for a given application pools in IIS 7.5.

By default, the machine.config file contains the following:

<system.web>
   <processModel autoConfig="true"/>
   ...
</system.web>

This means that ASP.NET automatically configures some critical attributes to achieve optimal performance. You might want to tweak some of these attributes to tailor a configuration for your specific application. Table 3-12 describes these attributes.

Table 3-12. Optimizing the ASP.NET Process Model

Attribute

Description

maxIoThreads

Indicates the maximum number of IO threads per CPU in the thread pool. The default is 20 (indicating a total of 20xN threads on a machine with N CPUs).

maxWorkerThreads

Indicates the maximum number of worker threads per CPU in the thread pool. The default is 20 (meaning a total of 20xN threads on a machine with N CPUs).

memoryLimit

Indicates the percentage of memory that the worker process can consume before being recycled by IIS. The number indicates the percentage of the total system memory. The default value is 60.

minIoThreads

Configures the minimum number of I/O threads to use for the process on a per-CPU basis. The default is 1.

minWorkerThreads

Configures the minimum amount of worker threads to use for the process on a per-CPU basis. The default is 1.

requestQueueLimit

Indicates the number of requests the ASP.NET process can queue before returning error 503 (Server too busy.) The default is 5000.

responseDeadlockInterval

Indicates the time after which a process with queued requests that has not returned a response is considered deadlocked and is shut down. The default is three minutes.

Let’s consider some alternatives, starting with memory limits. The default value of 60 has been determined by looking at an average scenario where your application is likely not to be the only one on the server. However, if you’re lucky enough to be the only server process that consumes memory, the number can set to a higher threshold such as 75 without raising significant issues.

I/O threads are threads used to perform asynchronous operations that tend to take a while to complete. The typical example is reading a file or calling into a Web service. I/O threads are implicitly set up by high-level code you call usually through BeginXxx methods. Worker threads are, instead, threads used for plain operations. You might want to increase the number of I/O threads or worker threads based on the characteristics of your application. As you might have noticed, two minimum settings exist for threads: minIoThreads and minWorkerThreads. These values determine the lower bound that, when reached, cause ASP.NET to queue successive requests. A new request for a worker process is queued when fewer than the minWorkerThreads free threads are counted. The same happens for I/O threads.

The <profile> Section

The <profile> section is used to configure storage and layout of the user-profiling feature. Basically, each user can be assigned a set of properties whose values are loaded and persisted automatically by the system when the request begins and ends. A profile provider takes care of any I/O activity using a particular data store. The default profile provider, for example, uses the AspNetDb.mdf file and SQL Server Express.

The <profile> section has the following schema:

<profile
    enabled="true|false"
    inherits="fully qualified type reference"
    automaticSaveEnabled="true|false"
    defaultProvider="provider name">
    <properties>...</properties>
    <providers>...</providers>
</profile>

The enabled attribute indicates whether user profiles are enabled. The default value is true. The set of properties that is associated with each authenticated user is defined in the <properties> child element:

<profile>
    <properties>
        <add name="BackColor" type="string" />
        <add name="ForeColor" type="string" />
    </properties>
</profile>

Table 3-13 lists the attributes allowed on the Profile property.

Table 3-13. Attributes of the Profile Property

Attribute

Description

allowAnonymous

Allows storing values for anonymous users. It’s false by default.

customProviderData

Contains data for a custom profile provider.

defaultValue

Indicates the default value of the property.

name

Name of the property.

provider

Name of the provider to use to read and write the property.

readOnly

Specifies whether the property value is read-only. It’s false by default.

serializeAs

Indicates how to serialize the value of the property. Possible values are Xml, Binary, String, and ProviderSpecific.

type

The .NET Framework type of property. It is a string object by default.

All properties are packaged in a dynamically created class that is exposed to user code through the Profile property on the HttpContext object. The Inherits attribute allows you to define the base class of this dynamically created profile class. The automaticSaveEnabled attribute specifies whether the user profile should be automatically saved at the end of the execution of an ASP.NET page. (The default is true.) Note that the profile is saved only if the HTTP module in charge of it detects that the profile has been modified.

The <providers> element lists all available profile providers. You use this section to register custom providers. The defaultProvider attribute indicates the currently selected provider that pages will use.

The <roleManager> Section

The <roleManager> section configures role management for an ASP.NET application. Role management is carried out by two components: an HTTP module that intercepts incoming requests, and a role provider that retrieves and sets role information for the authenticated user. The provider acts as a proxy for the data store where the role information is stored. All available providers are listed in the <providers> child section. A new provider should be added here. The default provider is specified in the defaultProvider attribute. The overall schema of the section is shown here:

<roleManager
    cacheRolesInCookie="true|false"
    cookieName="name"
    cookiePath="/"
    cookieProtection="All|Encryption|Validation|None"
    cookieRequireSSL="true|false "
    cookieSlidingExpiration="true|false "
    cookieTimeout="number of minutes"
    createPersistentCookie="true|false"
    defaultProvider="provider name"
    domain="cookie domain">
    enabled="true|false"
    maxCachedResults="maximum number of role names cached"
    <providers>...</providers>
</roleManager>

After the HTTP module receives the role information from the currently selected provider, it usually creates a cookie to cache the information for future requests. All cookie-related attributes you see in the schema configure a different aspect of the cookie. The default name is .ASPXROLES.

The <securityPolicy> Section

In the <securityPolicy> section, you define mappings between security levels and policy files. The section can be configured at the application level but not in subdirectories. The section contains one or more <trustLevel> elements with name and policyFile attributes. You also can use the section to extend the security system by providing your own named trust levels mapped to a custom security policy file.

Here’s an excerpt from the site’s root web.config file that ASP.NET installs:

<securityPolicy>
    <trustLevel name="Full" policyFile="internal" />
    <trustLevel name="High" policyFile="web_hightrust.config" />
    <trustLevel name="Medium" policyFile="web_mediumtrust.config" />
    <trustLevel name="Low"  policyFile="web_lowtrust.config" />
    <trustLevel name="Minimal" policyFile="web_minimaltrust.config" />
</securityPolicy>

The name attribute can be set to Full, High, or Low in all versions of the .NET Framework. Each trust level identifies a particular security level that you map to a policy file. Security policy files are XML files located in the same folder as machine.config.

Notice that in ASP.NET the Full level of trust doesn’t need to have an associated policy file full of permission sets and code-group definitions. The reason is that ASP.NET doesn’t add extra security settings in the case of Full trust, so in such cases the content of the policyFile attribute is ignored.

The <sessionState>Section

The <sessionState> section stores session-state settings for the current application. The section determines the behavior and implementation details of the ASP.NET Session object. The Session object can work in different modes to accommodate the application’s requirements for performance, robustness, and data reliability. In Table 3-14, you can see the list of acceptable attributes for the element. The mode attribute is the only mandatory attribute. Some attributes are mutually exclusive.

Table 3-14. Session-State Attributes

Attribute

Description

allowCustomSqlDatabase

If this is set to true, it enables you to specify a custom SQL Server database to store session data instead of using the default ASPState database.

compressionEnabled

Specifies whether compression is applied to the session-state data.

cookieless

Specifies how to communicate the session ID to clients. Feasible values are those listed in Table 3-5.

cookieName

Name of the cookie, if cookies are used for session IDs.

customProvider

Name of the custom session-state store provider to use for storing and retrieving session-state data.

mode

Specifies the implementation mode of the session state. Acceptable values are Off, InProc, Custom, StateServer, and SQLServer. When it’s set to Off, session-state management is disabled and the Session object is not available to the application. InProc is the default working mode, and it stores session data locally in the Web server’s memory. Alternatively, the session state can be stored on a remote server (StateServer) or in a SQL Server database (SQLServer). The Custom option indicates that the application is using a custom data store.

partitionResolverType

Indicates the type and assembly of the partition resolver component to be loaded to provide connection information when session state is working in SQLServer or StateServer mode. If a partition resolver can be correctly loaded, the sqlConnectionString and stateConnectionString attributes are ignored.

regenerateExpiredSessionId

When a request is made with a session ID that has expired, if this attribute is true, a new session ID is generated; otherwise, the expired one is revived. The default is false.

sessionIDManagerType

Null by default. If this attribute is set, it indicates the component to use as the generator of session IDs.

sqlCommandTimeout

Specifies the number of seconds a SQL command can be idle before it is canceled. The default is 30.

sqlConnectionRetryInterval

Specifies the time interval, in seconds, between attempts to connect to the database. The default is 0.

sqlConnectionString

Used when the mode is set to SQLServer; specifies the connection string for the SQL Server database to use for storing session data.

stateConnectionString

Used when the mode is set to StateServer; specifies the server name and port where session state should be stored.

stateNetworkTimeout

Specifies the number of seconds the TCP/IP network connection between the Web server and the state server can be idle before the request is canceled. The default is 10.

timeout

Specifies the number of minutes a session can be idle before it is abandoned. The default is 20.

useHostingIdentity

Indicates that the ASP.NET process identity is impersonated to access a custom state provider or the SQLServer provider configured for integrated security. It’s true by default.

In addition, the child <providers> section lists custom session-state store providers. ASP.NET session state is designed to enable you to easily store user session data in different sources, such as a Web server’s memory or SQL Server. A store provider is a component that manages the storage of session-state information and stores it in alternative media (for example, an Oracle database) and with an alternative layout.

The default connection string for the SQLServer mode is set to the following:

data source=127.0.0.1;Integrated Security=SSPI

As you can see, it doesn’t contain the database name, which defaults to AspState. You create this database before the application is released using either T-SQL scripts or the aspnet_regsql command-line utility.

The default connection string for the StateServer mode is set to

tcpip=127.0.0.1:42424

You can change the TCP/IP address and the port used at will. Note, though, that to change the port you must edit the Port entry under the registry key:

HKEY_LOCAL_MACHINE
   SYSTEMCurrentControlSetServicesaspnet_stateParameters

In other words, just writing the new port number in the configuration file is not enough.

The <siteMap> Section

The <siteMap> section configures settings and providers for the ASP.NET site navigation system. The schema of the section is quite simple:

<sitemap
  enabled="true|false"
  defaultProvider="provider name">
  <providers>...</providers>
</siteMap>

The feature relies on site-map providers—that is, made-to-measure components that return information representing the structure of the site. ASP.NET comes with one predefined provider: the AspNetXmlSiteMapProvider class. The default site-map provider is specified through the defaultProvider attribute. All available providers, including custom providers, are listed in the <providers> section.

The <trace> Section

Tracing refers to the program’s ability to send informative messages about the status of the execution. In general, tracing is a way to monitor the behavior of an application in a production environment, and debugging is used for development time testing. The <trace> section defines attributes that can modify the behavior of application-level tracing. The attributes are listed in Table 3-15.

Table 3-15. Application-Level ASP.NET Tracing Attributes

Attribute

Description

enabled

Specifies whether tracing is enabled for an application. The default is false. Tracing must be enabled in order to use the trace viewer (trace.axd) and other tracing facilities.

localOnly

If this attribute is set to true, the trace viewer is available only on the local host; if it’s set to false, the trace viewer is also available remotely. The default is true. Note that trace.axd is one of the default HTTP handlers registered at installation time.

pageOutput

Specifies whether trace output is rendered at the end of each page. If this attribute is set to false, trace output is accessible through the trace viewer only. The default is false. Regardless of this global setting, individual pages can enable tracing using the Trace attribute of the @Page directive.

requestLimit

Indicates the maximum number of trace results to store on the server that are subsequently available through trace.axd. The default value is 10. The maximum is 10,000.

traceMode

Indicates the criteria by which trace records are to be sorted and displayed. Acceptable values are SortByTime (the default) or SortByCategory. Sorting by time means that records are displayed in the order in which they are generated. A category, on the other hand, is a user-defined name that can be optionally specified in the trace text.

writeToDiagnosticsTrace

This is false by default. It specifies whether trace messages should be forwarded to the diagnostics tracing infrastructure, for any registered listeners.

In the .NET Framework, tracing is provided through a unified, abstract API that uses ad hoc drivers to physically output the messages. These drivers are called listeners and redirect the tracing output to the specified target—typically a log file or an output stream. Listeners are defined in the <system.diagnostics> section. When writeToDiagnosticsTrace is true, any ASP.NET-generated trace message is also forwarded to all registered listeners.

The <trust> Section

The <trust> section configures the trust level under which the application will be run and determines the code-access security (CAS) restrictions applied to the application. By default, all ASP.NET applications run on the Web server as fully trusted applications and are allowed to do whatever their account is allowed to do. The CLR doesn’t sandbox the code. Hence, any security restrictions applied to an application (for example, the inability to write files or write to the registry) are not the sign of partial trust but simply the effect of the underprivileged account under which ASP.NET applications normally run. Here’s the schema for the section:

<trust
   hostSecurityPolicyResolverType ="security policy resolution type"
   legacyCasModel = "[True|False]"
   level="[Full|High|Medium|Low|Minimal]"
   originUrl="URL"
   permissionSetName = "name of the permission set"
   processRequestInApplicationTrust = "[True|False]"
/>

You act on the <trust> section if you want to run a Web application with less than full trust. The following code snippet shows the default <trust> setting in the site root web.config:

<trust level="Full" originUrl="" />

Allowable values for the level attribute are all the <trustLevel> entries defined in the <securityPolicy> section.

The originUrl attribute is a sort of misnomer. If you set it, what really happens is quite simple: the application is granted the permission of accessing the specified URL over HTTP using either a Socket or WebRequest class. Of course, the Web permission is granted only if the specified <trust> level supports that. Medium and higher trust levels do.

The <trust> section supports a Boolean attribute named processRequestInApplicationTrust. If true (the default), the attribute dictates that page requests are automatically restricted to the permissions in the trust policy file applied to the application. If it’s false, there’s the possibility that a page request runs with higher privileges than set in the trust policy.

Note

The <trust> section is allowed only at the machine level and application level because of technical reasons, not because of security concerns. An ASP.NET application runs in its own AppDomain, and the trust level for that application is set by applying the appropriate security policy to the AppDomain. Although policy statements can target specific pieces of code, the AppDomain is the lowest level at which a security policy can be applied. If the CLR has a policy level more granular than the AppDomain, you can define different trust levels for various portions of the ASP.NET application.

The following script shows how to specify Medium trust-level settings for all applications on a server. The script is excerpted from a site’s root web.config file. With allowOverride set to false, the trust level is locked and cannot be modified by the application’s root web.config file.

<location allowOverride="false">
  <system.web>
    <trust level="Medium" originUrl="" />
  </system.web>
</location>

By adding the following script, instead, you release the lock for a particular application on the machine:

<location allowOverride="true" path="Default Web Site/MySite40">
  <system.web>
    <trust level="Medium" originUrl="" />
  </system.web>
</location>

With the .NET Framework 4, Microsoft made some significant changes to the CAS model for managed applications. These changes might actually cause some ASP.NET applications to fail. At risk are partial-trust ASP.NET applications that either rely on trusted code running in the global assembly cache (GAC) or require extensive modifications to machine CAS policy files. For this reason, the legacyCasModel attribute has been added to revert partial-trust ASP.NET 4 applications to the behavior of earlier versions of ASP.NET built for earlier versions of the CLR. All you do is set legacyCasModel to true if you want to include a legacy CAS-related behavior from your ASP.NET 4 application.

In ASP.NET 4, there are various ways of associating a permission set with any assemblies required by the application. As in earlier versions, you can shape up the permission set by editing the partial-trust policy file for an individual trust level (for example, web_mediumtrust.config). In addition, you can specify a permission set explicitly through the PermissionSetName attribute. In ASP.NET 4, there are three possible permission sets: FullTrust, ASP.Net, and Nothing.

The FullTrust permission set makes any code run as fully trusted. The ASP.Net permission set is typically used for partial-trust applications and is the default name assigned to the PermissionSetName attribute. Nothing is not really an alternate permission set; rather, it is simply the empty permission set. The CLR throws a security exception for any assembly associated with the empty permission set. When you change the name of the permission set, ASP.NET 4 will search the partial-trust policy file with the same name.

Note

Changing the name of the default partial trust permission set is not an action you want to take without a valid reason. The feature exists mostly for when you need a SharePoint application to define its own set of permissions distinct from those of typical ASP.NET applications. Keep in mind that with the new CAS model of the .NET Framework 4, you are no longer allowed to have multiple named permission sets to define partial-trust permissions. So you can change the name from ASP.Net to something else, but that won’t give you multiple partial trust permission sets for each application.

Finally, you can also opt for a programmatic approach to the task of choosing the permission set for an assembly. The CLR queries a HostSecurityManager object every time an assembly is loaded. One of the tasks associated with the HostSecurityManager type is returning the permission set for the assembly being loaded. In ASP.NET 4, you can gain control over this process by defining your own resolver type. A resolver type is registered through the hostSecurityPolicyResolverType attribute and consists of a type derived from the system’s HostSecurityPolicyResolver type. I’ll return to CAS for ASP.NET 4 applications in Chapter 19. You can find some good literature about this topic at http://msdn.microsoft.com/en-us/library/dd984947%28VS.100%29.aspx.

The <urlMappings> Section

The <urlMappings> section contains a list of mappings between fake URLs and real endpoints in the application. Here’s a quick example that is worth a thousand words:

<urlMappings enabled="true">
   <add url="~/main.aspx" mappedUrl="~/default.aspx?tab=main" />
</urlMappings>

The url attribute indicates the URL that users request from their browser. The mappedUrl attribute indicates the corresponding URL that is passed on to the application. Both URLs are application-relative. In addition to the <add> node, the <urlMappings> section also supports the <remove> and <clear> nodes.

Note

The <urlMappings> section was introduced as the declarative counterpart of the RewritePath method defined on the HttpContext class. In ASP.NET 4, the URL-rewriting API has been further improved with the introduction of routing. You might want to choose the new routing API as your first option in an ASP.NET 4 application. (I’ll cover routing in the next chapter.)

The <webControls> Section

The <webControls> section contains only the clientScriptsLocation attribute that specifies the default path to ASP.NET client script files. These files are included in the HTML code generated for .aspx pages when these pages require client-side functionalities such as smart navigation and client-side control validation.

<webControls clientScriptsLocation="/aspnet_client/{0}/{1}/" />

The preceding code snippet represents the default contents of the <webControls> section. The content of clientScriptsLocation, properly expanded, is the URL used for searching scripts to be included. The aspnet_client directory is automatically created under the Web server’s root when you install ASP.NET. The two placeholders in the string represent subdirectories whose name might change in future versions of ASP.NET. The first placeholder is always set to system_web. The second placeholder expands to a subdirectory name based on the version of the .NET Framework.

ASP.NET 4 doesn’t use this folder to store client script files. Client script files are, in fact, embedded as resources in the system.web assembly and are injected in pages through the webresource.axd HTTP handler.

You can use the client script folder to store script files employed by any custom ASP.NET controls you might write.

The <xhtmlConformance> Section

The <xhtmlConformance> section designates the XHTML rendering mode for an application. The default rendering for pages and controls is XHTML 1.0 Transitional. This is also the default for new pages created in Microsoft Visual Studio 2010. You can configure the preferred rendering by setting options in the <xhtmlConformance> section, which enables you to select XHTML 1.0 Transitional, XHTML1.0 Strict, and legacy rendering.

<xhtmlConformance mode="Transitional|Legacy|Strict"/>

If you opt for Legacy, pages and controls will render as in ASP.NET 1.x.

Other Top-Level Sections

The sections under the <system.web> element don’t exhaust the list of configuration elements that are useful to ASP.NET developers. At least three other sections should be known and mastered.

The <appSettings> Section

The <appSettings> section stores custom application configuration data such as file paths, URLs of interest, or any other application-wide information:

<configuration>
    <appSettings>
        <add key="DefaultCacheDurationForData" value="..." />
    </appSettings>
</configuration>

The syntax of the <appSettings> section is defined as follows:

<appSettings>
    <add key="..." value="..." />
    <remove key="..." />
    <clear />
</appSettings>

The <add> element adds a new setting to the internal collection. This new setting has a value and is identified by a unique key. The <remove> element removes the specified setting from the collection. The setting is identified using the key. Finally, the <clear> element clears all settings that have previously been defined in the section.

As the name of the section implies, you should store in the section application-specific settings and avoid storing user-specific information. For user-specific information, you can use the user profile API. (See Chapter 8.)

Any contents you design for storage in the <appSettings> section can be saved to an external XML file that is linked to the section through the file attribute:

<appSettings file="myfile.config" />

The content of the file pointed to by the file attribute is read as if it is an <appSettings> section in the web.config file. Note that the root element of the file must match <appSettings>.

Note

Changes to the external file are not detected until the application is restarted. If you incorporate <appSettings> in the web.config file, any changes are instead detected in real time.

The <connectionStrings> Section

The section is specifically designed to contain connection strings and is laid out as follows:

<connectionStrings>
    <add name="NWind"
        connectionString="SERVER=...;DATABASE=...;UID=...;PWD=...;"
        providerName="System.Data.SqlClient"  />
</connectionStrings>

You can manipulate the contents of the section by using <add>, <remove>, and <clear> nodes. Each stored connection is identified with a name you set through the name attribute. The connection parameters are set in the connectionString attribute. Finally, the providerName attribute indicates the ADO.NET data provider to use.

Connection names are also used within the configuration file to link a connection string to other sections, typically the <providers> section of <membership> and <profile> nodes.

Note

You are not really forced to place all of your connection strings in the <connectionStrings> section. You can place your strings in <appSettings> as well as in a custom section. Look at this section as a system facility for a common task you would accomplish anyway.

The <configProtectedData> Section

ASP.NET lets you encrypt specific sections of configuration files that might contain sensitive data. It does that through industry-standard XML encryption. XML encryption (which you can learn more about at http://www.w3.org/TR/xmlenc-core) is a way to encrypt data and represent the result in XML.

Encryption of configuration sections is optional, and you can enable it for any configuration sections you want by running a command-line tool, as you’ll see later in this chapter in the section Managing Configuration Data.

You can specify the type of encryption you want by selecting the appropriate provider from the list of available encryption providers. The .NET Framework 4.0 comes with two predefined providers: DPAPIProtectedConfigurationProvider and RSAProtectedConfigurationProvider. The former uses the Windows Data Protection API (DPAPI) to encrypt and decrypt data; the latter (the default provider) uses the RSA encryption algorithm to encrypt and decrypt data.

Most configuration sections that are processed by the managed configuration system are eligible for protection. The <configProtectedData> section itself, though, can’t be protected. In this case, clear text is necessary to describe the behavior of the system. Similarly, sections consumed by the CLR from Win32 code or from ad hoc managed XML parsers can’t be protected by this system because they don’t employ section handlers to consume their configuration. This includes at least the following sections: <processModel>, <runtime>, <mscorlib>, <startup>, and <system.runtime.remoting>.

The <system.web.extensions> Section

This section contains elements that configure AJAX-related services and control their behavior. The section is laid out as shown here:

<system.web.extensions>
   <scripting>
     <scriptResourceHandler
           enableCompression="true|false"
           enableCaching="true|false" />
   </scripting>
   <webServices>
      <jsonSerialization ... />
      <authenticationService ... />
      <roleService ... />
      <profileService ... />
   </webServices>
</system.web.extensions>

The scriptResourceHandler element allows you to specify whether script files embedded as resources in a given application assembly are to be cached or compressed. Both options are false by default.

The content of the <webServices> element is related to Web or WCF services used by AJAX-enabled applications. The <jsonSerialization> element configures JSON serialization and is made of two attributes: maxJsonLength and recursionLimit. The former indicates the maximum length of a JSON string; the latter sets the maximum level of nesting allowed in the type being serialized.

The <authenticationService> element configures the ASP.NET authentication API exposed as a Web service to ASP.NET AJAX applications. The section has only two Boolean attributes: enabled and requireSSL. Both are false by default.

The <roleService> element configures the ASP.NET role management API exposed as a Web service to ASP.NET AJAX applications. The section has only Boolean attribute—enabled—which is false by default.

The <profileService> element configures the ASP.NET profile API exposed as a Web service to ASP.NET AJAX applications. The section has three attributes—enabled, readAccessProperties, and writeAccessProperties. The latter two properties consist of a list of comma-separated names of properties to be read and written as part of the user’s profile.

The <system.webServer> Section

In general, the <system.webServer> section contains site-level settings for IIS 7.x. Defined within the applicationHost.config file and edited via the user interface of IIS Manager, the section specifies any settings used by the Web server engine and modules. Full documentation is available at http://www.iis.net/ConfigReference/system.webServer.

The section can also be used within the application’s web.config file to make some of the settings specific to a given application. There’s a specific situation, though, that requires you to have a <system.webServer> section in the application’s web.config file—an ASP.NET application that employs HTTP modules, HTTP handlers, or both and runs under IIS 7.x in integrated mode.

Before IIS 7 came along, any ASP.NET request had to go through two distinct pipelines: one right at the IIS gate, and one mapped to the ASP.NET runtime environment. Subsequently, an ASP.NET application in need of supporting special HTTP modules or handlers simply registered them in the web.config file and waited for them to be invoked. In IIS 7 integrated mode, instead, the request pipeline is unified at the IIS level. As a result, any HTTP handlers and HTTP modules you might have registered in the <httpHandlers> and <httpModules> sections of the web.config file will be blissfully ignored.

For an IIS 7–integrated ASP.NET application to properly deal with HTTP modules and handlers, you have to move the <httpHandlers> and <httpModules> sections to a new <system.webServer> section in the same application’s web.config file. There are some snags though.

Important

When developing HTTP handlers and modules, you should be aware of a key point. The ASP.NET Development Server (also known as Cassini) doesn’t honor the content of the <webServer> section. This means that, for development purposes only, you should copy the registration of your handlers and modules also in the <httpHandlers> and <httpModules> section, regardless of whether your application will actually be deployed on IIS 7. The ASP.NET Development Server that comes with Visual Studio is designed to capture and process all requests within its own pipeline; in this regard, its overall behavior is more similar to IIS 6 than IIS 7.

Under <system.webServer>, sections have been renamed <modules> and <handlers> and have a slightly different set of attributes. In particular, each handler must have a name attribute and support additional attributes, namely precondition and allowpolicy. The precondition attribute lists what’s required for the handler to work: type of pipeline (classicMode or integratedMode), bitness (32 or 64), and runtime version of ASP.NET (v2 or v4). The allowPolicy attribute sets the permissions granted to the handler: read, write, execute, or script.

The <modules> section counts a couple of Boolean attributes, such as runAllManagedModulesForAllRequests and runManagedModulesForWebDavRequests. Both properties default to false. This is the typical content for <system.webServer> in a new ASP.NET 4 application in Visual Studio 2010.

<modules runAllManagedModulesForAllRequests="true">
</modules>

The attribute runAllManagedModulesForAllRequests indicates that all managed modules can process all requests, even if the request was not for managed content. Instead, the attribute runManagedModulesForWebDavRequests specifies whether managed modules can process WebDAV requests.

These differences between classic and integrated mode lead you toward using different web.config files to set up handlers and modules for the same application deployed in different scenarios. By using the <validation> element, however, you can have a single web.config file with settings for both classic and integrated IIS 7 working modes:

<system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    ...
   </system.webServer>

The <validation> element tells IIS not to validate the schema of the web.config file against the known configuration schema of integrated mode. In this way, when you are working in integrated mode, <httpHandlers> and <httpModules> are ignored; and when you are in classic mode, the entire <system.webServer> section is ignored.

Note

If you’re having trouble while hosting an ASP.NET application under IIS 7.x in integrated mode, you might want to read the following article for more information and a very good background of the whole topic: http://learn.iis.net/page.aspx/381/aspnet-20-breaking-changes-on-iis-70.

Managing Configuration Data

Configuration data can be managed by developers and administrators in two main ways: programmatically through an ad hoc API, and manually through command-line utilities, XML editors, or perhaps the Web Site Administration Tool (WSAT). Let’s take a closer look at these options.

Using the Configuration API

ASP.NET includes a full configuration management API that enables you to navigate, read, and write an application’s configuration files. Configuration settings are exposed as a set of strongly typed objects that you can easily program against. These classes—one for each section in the overall schema—are all defined in the System.Configuration namespace.

The configuration API is smart enough to provide a merged view of all the settings that apply to that level. When settings are modified, the API automatically writes changes to the correct node in the correct configuration file. The management API can be used to read and write configuration settings of local and remote applications. Custom configuration sections are automatically manageable through the API.

Retrieving Web Configuration Settings

You use the WebConfigurationManager class to get access to the ASP.NET configuration files. The class is the preferred way to work with configuration files related to Web applications. The following code snippet illustrates how to retrieve the HTTP handlers in use in the current application:

void Button1_Click(object sender, EventArgs e)
{
   var name = @"system.web/httpHandlers";
   var cfg = WebConfigurationManager.OpenWebConfiguration("/");
   var handlers = (HttpHandlersSection) cfg.GetSection(name);
   EnumerateHandlers(handlers);
}

void EnumerateHandlers(HttpHandlersSection section)
{
   foreach (var handler in section.Handlers)
   {
      ...
   }
}

You open the configuration file using the OpenWebConfiguration method. The parameter you pass to the method indicates the level at which you want to retrieve information. If you specify null or /, you intend to capture configuration data at the site’s root level. If you want information at the machine level, you resort to the OpenMachineConfiguration method.

The OpenWebConfiguration method returns a Configuration object on which you can call GetSection to retrieve the contents of a particular section. For HTTP handlers, you do as follows:

HttpHandlersSection section;
section = (HttpHandlersSection) cfg.GetSection(@"system.web/httpHandlers");

Each section class has a programming interface that closely reflects the attributes and child sections on the element.

To access configuration data at the application level, you pass the application’s URL to the OpenWebConfiguration method:

var path = Request.CurrentExecutionFilePath;
Configuration cfg = WebConfigurationManager.OpenWebConfiguration(path);

To retrieve information about other sections, you use the same pattern illustrated earlier by changing section names and section classes.

Note

The .NET Framework offers two similar classes to achieve the same goals: the aforementioned WebConfigurationManager and ConfigurationManager. Their functionalities overlap to a good extent, but they are not the same thing. In particular, they do the same thing if all you need to do is read data from mapped sections such as AppSettings and ConnectionStrings If you need to access a specific section, remember that WebConfigurationManager can be configured to open a Web configuration file, whereas ConfigurationManager is designed for other types of applications.

Retrieving Application Settings

As mentioned, most ASP.NET applications need to access data in sections outside the <system.web> element. Canonical examples are <appSettings> and <connectionString>. For sections not included in the <system.web> element, you normally use the ConfigurationManager class. However, WebConfigurationManager contains a couple of helper public properties to access AppSettings and ConnectionStrings collections. The following code snippet shows the implementation of these properties in WebConfigurationManager:

public static NameValueCollection AppSettings
{
    get {return ConfigurationManager.AppSettings;}
}

public static NameValueCollection ConnectionStrings
{
    get {return ConfigurationManager.ConnectionStrings;}
}

As you can see, to access application settings and connection strings you can interchangeably use the AppSettings and ConnectionStrings collections on both WebConfigurationManager and ConfigurationManager. Here’s how to obtain a registered connection string named Northwind:

WebConfigurationManager.ConnectionStrings["Northwind"].ConnectionString

For a value stored in the <appSettings> section, you need the following:

WebConfigurationManager.AppSettings["CacheDurationForData"]

In case you need to access other sections outside <system.web>, the ConfigurationManager class supplies the OpenMachineConfiguration method to access the tree of configuration data. Here’s the code to retrieve the supported protocol prefixes for Web requests (https, http, ftp, and the like):

var name = @"system.net/webRequestModules";
Configuration cfg = ConfigurationManager.OpenMachineConfiguration();
var section = (WebRequestModulesSection) cfg.GetSection(name);
foreach (WebRequestModuleElement m in section.WebRequestModules)
{
   ...
}

To explore the content of a section, you need to cast the return value of the GetSection method to a specific type. A section type is defined for each system-provided supported section in the system.configuration assembly. Note, though, that you won’t find any such section classes for elements under the <system.webServer> section. If you need to programmatically read or write within the <system.webServer> section, you must reference the Microsoft.Web.Administration assembly where such classes are defined. You find the assembly in the IIS folder, specifically under System32inetsrv.

Updating Application Settings

The entire content of the configuration tree is exposed to applications through a sort of Document Object Model (DOM). This DOM is modifiable in memory. After you’re done, you can persist changes by calling the Save method on the corresponding Configuration class. The following code snippet shows how to programmatically add a new HTTP handler to the current application:

var name = @"system.web/httpHandlers";
var path = "/myapp";

var config = WebConfigurationManager.OpenWebConfiguration(path);
var section = (HttpHandlersSection) config.GetSection(name);

var newHandler = new HttpHandlerAction("*.xyz", "System.Web.HttpForbiddenHandler", "*");
section.Handlers.Add(newHandler);
config.Save();

The newly added handler configures the system so that requests for .xyz files are blocked. The application’s web.config file is modified as follows:

<httpHandlers>
   ...
   <add path="*.xyz"
        verb="*"
        type="System.Web.HttpForbiddenHandler" />
</httpHandlers>

To re-enable .xyz resources, you need to remove the handler that was just added. The following code shows how to proceed programmatically:

var name = @"system.web/httpHandlers";
var path = "/myapp";

var config = WebConfigurationManager.OpenWebConfiguration(path);
var section = (HttpHandlersSection) config.GetSection(name);

section.Handlers.Remove("*", "*.xyz");
config.Save();

After this, any request for an .xyz resource is likely to produce the, perhaps more familiar, “resource not found” message.

Encrypting a Section

With the exceptions listed earlier while discussing the <protectedData> section, all sections in a configuration file can be encrypted both programmatically using the configuration API and in offline mode using a command-line tool. Let’s tackle this latter option first.

Using a Command-Line Tool

You use the newest version of a popular system tool: aspnet_regiis.exe. Here’s a sample usage of the utility to encrypt connection strings for the /MyApp application. Note that the section names are case-sensitive.

aspnet_regiis.exe -pe connectionStrings -app /MyApp

After running this command, the web.config looks different. The <connectionStrings> section now incorporates a child <EncryptedData> section, which is where the ciphered content has been stored. If you open the web.config file after encryption, you see something like the following:

<configuration>
  <connectionStrings
     configProtectionProvider="RsaProtectedConfigurationProvider">
    <EncryptedData ...>
      ...
      <CipherData>
        <CipherValue>cQyofWFQ ... =</CipherValue>
      </CipherData>
    </EncryptedData>
  </connectionStrings>
</configuration>

To restore the web.config file to its original clear state, you use the –pd switch in lieu of –pe in the aforementioned command line. The nice part of the story is that this form of encryption is completely transparent to applications, which continue working as before.

Using a Programmatic Approach

To encrypt and decrypt sections programmatically, you use the ProtectSection and UnprotectSection methods defined on the SectionInformation object. Here’s how to proceed:

var name = "connectionStrings";
var path = "/myApp";
var provider = "RsaProtectedConfigurationProvider";

var config = WebConfigurationManager.OpenWebConfiguration(path);
var section = (ConnectionStringsSection) cfg.GetSection(name);

section.SectionInformation.ProtectSection(provider);
config.Save();

To unprotect, you change the call to ProtectSection with the following:

section.SectionInformation.UnprotectSection();
config.Save();

Note that to persist changes it is still essential to place a call to the Save method on the Configuration object.

Choosing the Encryption Provider

Any page that uses protected sections works like a champ as long as you run it inside the local Web server embedded in Visual Studio. You might get an RSA provider configuration error if you access the same page from within a canonical (and much more realistic) IIS virtual folder. What’s up with that?

The RSA-based provider—the default protection provider, if you use the command-line tool—needs a key container to work. A default key container is created upon installation and is named NetFrameWorkConfigurationKey. The aspnet_regiis.exe utility provides a lot of command-line switches for you to add, remove, and edit key containers. The essential point is that you have a key container created before you dump the RSA-protected configuration provider. The container must not only exist, but it also needs to be associated with the user account attempting to call it. The system account (running the local Web server) is listed with the container; the ASP.NET account on your Web server might not be. Note that granting access to the key container is necessary only if you use the RSA provider.

Assuming you run ASP.NET under the NETWORK SERVICE account (the default on Windows Server 2003 machines), you need the following code to add access to the container for the user:

aspnet_regiis.exe -pa "NetFrameworkConfigurationKey"
         "NT AUTHORITYNETWORK SERVICE"

It is important that you specify a complete account name, as in the preceding code. In IIS 7.5 where ApplicationPoolIdentity is used by default in lieu of NETWORK SERVICE, how would you identify the account exactly? Here’s how:

aspnet_regiis.exe -pa "NetFrameworkConfigurationKey"
         "IIS APPPOOLYourAppPool"

You use IIS APPPOOL followed by the name of the IIS application pool whose identity you want to retrieve.

Both the RSA and DPAPI providers are great options for encrypting sensitive data. The DPAPI provider dramatically simplifies the process of key management—keys are generated based on machine credentials and can be accessed by all processes running on the machine. For the same reason, the DPAPI provider is not ideal to protect sections in a Web-farm scenario, where the same encrypted web.config file will be deployed to several servers. In this case, either you manually encrypt all web.config files on each machine or you copy the same container key to all servers. To accomplish this, you create a key container for the application, export it to an XML file, and import it on each server that will need to decrypt the encrypted web.config file. To create a key container, you do as follows. Using the command-line utility is mandatory here.

aspnet_regiis.exe -pc YourContainerName -exp

Next, you export the key container to an XML file:

aspnet_regiis.exe -px YourContainerName YourXmlFile.xml

Next, you move the XML file to each server and import it as follows:

aspnet_regiis.exe -pi YourContainerName YourXmlFile.xml

As a final step, grant the ASP.NET account permission to access the container.

Note

For more information about the aspnet:_regiis tool and its command line, refer to the following URL: http://msdn.microsoft.com/en-us/library/k6h9cz8h(VS.80).aspx.

Creating Custom Configuration Sections

The predefined XML schema for configuration files fits the bill in most cases, but when you have complex and structured information to persist, none of the existing schemas appear to be powerful enough. At this point, you have two possible workarounds. You can simply avoid using a standard configuration file and instead use a plain XML file written according to the schema you feel is appropriate for the data. Alternatively, you can embed your XML configuration data in the standard application configuration file but provide a tailor-made configuration section handler to read it.

Creating a new section (plus an optional new section group) requires editing the web.config file to register the section (or section group). While registering the new section, you need to specify the section handler component—that is, the piece of software in charge of parsing the contents of the section to processable data. Depending on what kind of data you’re going to store in the section, you can use one of the existing handlers or, more likely, create your own section handler.

In ASP.NET, the configuration section handler is a class that ultimately inherits from the ConfigurationSection class. The section handler class defines public properties and maps them to attributes in the XML element. In addition, these class properties are decorated with a special attribute named ConfigurationProperty. The following example shows how to create the handler for a new <MyPages> section with just one attribute—pageBackColor:

public class MyPagesSection : ConfigurationSection
{
   private static readonly ConfigurationProperty propPageBackColor = null;

   static MyPagesSection()
   {
      MyPagesSection.propPageBackColor = new ConfigurationProperty(
         "PageBackColor", typeof(string), "yellow",
          ConfigurationPropertyOptions.IsRequired);
   }

   [ConfigurationProperty("pageBackColor")]
   public string PageBackColor
   {
       get { return (string) base[MyPagesSection.propPageBackColor]; }
       set { base[MyPagesSection.propPageBackColor] = value; }
   }
}

The mapping between a property and a section attribute is established through the ConfigurationProperty attribute. The parameter of the attribute constructor indicates the name of the section attribute used to feed the decorated property.

A custom section must be registered to work properly. Here’s how to do it:

<configuration>
  <configSections>
     <section name="myPages"
            type="Samples.MyPagesSection, Samples" />
  </configSections>
  ...
<configuration>

The type property in the <section> tag indicates the class being used to read and write the contents of the section. For the sample <myPages> section, the system will use the MyPagesSection class in the specified assembly. If the assembly is strongly typed and located in the GAC, you should indicate its full name.

Summary

ASP.NET applications have many configurable settings. The various settings can all be controlled at different levels and overridden, extended, or restricted as appropriate. ASP.NET configuration is hierarchical by nature and lets you apply different configuration schemes at various levels of granularity—the machine, the Web site, the application, and even the folder.

Configuration files are probably the most critical aspect to consider when preparing the deployment of ASP.NET applications. Arranging a setup program has never been as easy as it is with Visual Studio (not considering third-party products), but deciding how to replicate the settings of the native environment might not be trivial. ASP.NET applications, in fact, can be deployed on a Web farm or in an ISP scenario, which requires particular care of the machine.config and web.config files.

Tweaking the content of the myriad sections you can have in a configuration file is a delicate art that requires awareness of the IIS runtime environment, the ASP.NET process model, and the endless list of settings and default values that this chapter attempted to cover in detail.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.186.124