Chapter 16. The HTTP Request Context

All great things are simple, and many can be expressed in single words.

Winston Churchill

Each ASP.NET request goes hand in hand with a companion object for its entire lifetime—an instance of the HttpContext class. The HttpContext object wraps up all the HTTP-specific information available about the request. It is then used by the various HTTP modules and used to group references to intrinsic worker objects such as Request, Response, and Server.

In this chapter, we’ll first review the startup process of the ASP.NET application and then move on to examine the various objects that form the context of the HTTP request.

Initialization of the Application

Each ASP.NET request is carried out by an ASP.NET application object. An ASP.NET application consists of an instance of the HttpApplication class that you briefly met in Chapter 2. HttpApplication is a global.asax-derived object that handles all HTTP requests directed to a particular virtual folder.

An ASP.NET running application is wholly represented by its virtual folder and, optionally, by the global.asax file. The virtual folder name is a sort of key that the HTTP runtime uses to selectively identify which of the running applications should take care of the incoming request. The global.asax file, if present, contains settings and code for responding to application-level events raised by ASP.NET or by registered HTTP modules that affect the application.

The particular HttpApplication selected is responsible for managing the entire lifetime of the request it is assigned to. That instance of HttpApplication can be reused only after the request has been completed. If no HttpApplication object is available, either because the application has not been started yet or all valid objects are busy, a new HttpApplication is created and pooled.

Properties of the HttpApplication Class

Although the HttpApplication provides a public constructor, user applications never need to create instances of the HttpApplication class directly. The ASP.NET runtime infrastructure always does the job for you. As mentioned, instances of the class are pooled and, as such, can process many requests in their lifetime, but always one at a time. Should concurrent requests arrive for the same application, additional instances are created. Table 16-1 lists the properties defined for the class.

Table 16-1. HttpApplication Properties

Property

Description

Application

Instance of the HttpApplicationState class. It represents the global and shared state of the application. It is functionally equivalent to the ASP intrinsic Application object.

Context

Instance of the HttpContext class. It encapsulates in a single object all HTTP-specific information about the current request. Intrinsic objects (for example, Application and Request) are also exposed as properties.

Modules

Gets the collection of modules that affect the current application.

Request

Instance of the HttpRequest class. It represents the current HTTP request. It is functionally equivalent to the ASP intrinsic Request object.

Response

Instance of the HttpResponse class. It sends HTTP response data to the client. It is functionally equivalent to the ASP intrinsic Response object.

Server

Instance of the HttpServerUtility class. It provides helper methods for processing Web requests. It is functionally equivalent to the ASP intrinsic Server object.

Session

Instance of the HttpSessionState class. It manages user-specific data. It is functionally equivalent to the ASP intrinsic Session object.

User

An IPrincipal object that represents the user making the request.

The HttpApplication is managed by the ASP.NET infrastructure, so how can you take advantage of the fairly rich, public programming interface of the class? The answer is that properties and, even more, overridable methods and class events can be accessed and programmatically manipulated in the global.asax file. (I’ll return to global.asax in a moment.)

Application Modules

The property Modules returns a collection of application-wide components providing ad hoc services. An HTTP module component is a class that implements the IHttpModule interface. Modules can be considered the managed counterpart of ISAPI filters; they are kind of request interceptors with the built-in capability of modifying the overall context of the request being processed. The Microsoft .NET Framework defines a number of standard modules, as listed in Table 16-2. Custom modules can be defined too. I cover this particular aspect of HTTP programming in Chapter 18.

Table 16-2. ASP.NET Modules

Module

Description

AnonymousIdentification

Assigns anonymous users a fake identity.

FileAuthorization

Verifies that the remote user has Microsoft Windows NT permissions to access the requested resource.

FormsAuthentication

Enables applications to use forms authentication.

OutputCache

Provides page output caching services.

PassportAuthentication

Provides a wrapper around Passport authentication services.

Profile

Provides user profile services.

RoleManager

Provides session-state services for the application.

ScriptModule

Used to implement page methods in AJAX pages.

SessionState

Provides session-state services for the application.

UrlAuthorization

Provides URL-based authorization services to access specified resources.

UrlRouting

Provides support for URL routing

WindowsAuthentication

Enables ASP.NET applications to use Windows and Internet Information Services (IIS)-based authentication.

The list of default modules is defined in the machine.config file. By creating a proper web.config file, you can also create an application-specific list of modules. (Configuration is covered in Chapter 3.)

Methods of the HttpApplication Class

The methods of the HttpApplication class can be divided into two groups: operational methods and event handler managers. The HttpApplication operational methods are described in Table 16-3.

Table 16-3. HttpApplication Operational Methods

Method

Description

CompleteRequest

Sets an internal flag that causes ASP.NET to skip all successive steps in the pipeline and directly execute EndRequest. It’s mostly useful to HTTP modules.

Dispose

Overridable method, cleans up the instance variables of all registered modules after the request has been served. At this time, Request, Response, Session, and Application are no longer available.

GetOutputCacheProviderName

Overridable method, returns the currently configured provider for handling output page caching. (I’ll say more about output page caching in Chapter 18.)

GetVaryByCustomString

Overridable method, provides a way to set output caching based on a custom string for all pages in the application. (I’ll say more about output page caching in Chapter 18.)

Init

Overridable method that executes custom initialization code after all modules have been linked to the application to serve the request. You can use it to create and configure any object that you want to use throughout the request processing. At this time, Request, Response, Session, and Application are not yet available.

Note that the Init and Dispose methods are quite different from well-known event handlers such as Application_Start and Application_End.

Init executes for every request directed to the Web application, whereas Application_Start fires only once in the Web application’s lifetime. Init indicates that a new instance of the HttpApplication class has been initialized to serve an incoming request; Application_Start denotes that the first instance of the HttpApplication class has been created to start up the Web application and serve its very first request. Likewise, Dispose signals the next termination of the request processing but not necessarily the end of the application. Application_End is raised only once, when the application is being shut down.

Note

The lifetime of any resources created in the Init method is limited to the execution of the current request. Any resource you allocate in Init should be disposed of in Dispose, at the latest. If you need persistent data, resort to other objects that form the application or session state.

In addition to the operational methods in Table 16-3, a few other HttpApplication methods are available to register asynchronous handlers for application-level events. These methods are of little interest to user applications and are used only by HTTP modules to hook up the events generated during the request’s chain of execution.

Events of the HttpApplication Class

Table 16-4 describes the event model of the HttpApplication class—that is, the set of events that HTTP modules, as well as user applications, can listen to and handle.

Table 16-4. HttpApplication Events

Event

Description

AcquireRequestState, PostAcquireRequestState

Occurs when the handler that will actually serve the request acquires the state information associated with the request.

AuthenticateRequest, PostAuthenticateRequest

Occurs when a security module has established the identity of the user.

AuthorizeRequest, PostAuthorizeRequest

Occurs when a security module has verified user authorization.

BeginRequest

Occurs as soon as the HTTP pipeline begins to process the request.

Disposed

Occurs when the HttpApplication object is disposed of as a result of a call to Dispose.

EndRequest

Occurs as the last event in the HTTP pipeline chain of execution.

Error

Occurs when an unhandled exception is thrown.

LogRequest, PostLogRequest

Occurs when the system logs the results of the request.

PostMapRequestHandler

Occurs when the HTTP handler to serve the request has been found.

PostRequestHandlerExecute

Occurs when the HTTP handler of choice finishes execution. The response text has been generated at this point.

PreRequestHandlerExecute

Occurs just before the HTTP handler of choice begins to work.

PreSendRequestContent

Occurs just before the ASP.NET runtime sends the response text to the client.

PreSendRequestHeaders

Occurs just before the ASP.NET runtime sends HTTP headers to the client.

ReleaseRequestState, PostReleaseRequestState

Occurs when the handler releases the state information associated with the current request.

ResolveRequestCache, PostResolveRequestCache

Occurs when the ASP.NET runtime resolves the request through the output cache.

UpdateRequestCache, PostUpdateRequestCache

Occurs when the ASP.NET runtime stores the response of the current request in the output cache to be used to serve subsequent requests.

To handle any of these events asynchronously, an application will use the corresponding method whose name follows a common pattern: AddOnXXXAsync, where XXX stands for the event name. To hook up some of these events in a synchronous manner, an application will define in the global.asax event handler procedures with the following signature:

public void Application_XXX(Object sender, EventArgs e)
{
    // Do something here
}

Of course, the XXX placeholder must be replaced with the name of the event from Table 16-4. All the events in the preceding table provide no event-specific data. You can also use the following simpler syntax without losing additional information and programming power:

public void Application_XXX()
{
    // Do something here
}

In addition to the events listed in Table 16-4, in global.asax an application can also handle Application_Start and Application_End. When ASP.NET is about to fire BeginRequest for the very first time in the application lifetime, it makes Application_Start precede it. EndRequest will happen at the end of every request to an application. Application_End occurs outside the context of a request, when the application is ending.

As you saw in Chapter 2, application events are fired in the following sequence:

  1. BeginRequest The ASP.NET HTTP pipeline begins to work on the request. This event reaches the application after Application_Start.

  2. AuthenticateRequest The request is being authenticated. All the internal ASP.NET authentication modules subscribe to this event and attempt to produce an identity. If no authentication module produced an authenticated user, an internal default authentication module is invoked to produce an identity for the unauthenticated user. This is done for the sake of consistency so that code doesn’t need to worry about null identities.

  3. PostAuthenticateRequest The request has been authenticated. All the information available is stored in the HttpContext’s User property.

  4. AuthorizeRequest The request authorization is about to occur. This event is commonly handled by application code to do custom authorization based on business logic or other application requirements.

  5. PostAuthorizeRequest The request has been authorized.

  6. ResolveRequestCache The ASP.NET runtime verifies whether returning a previously cached page can resolve the request. If a valid cached representation is found, the request is served from the cache and the request is short-circuited, calling only any registered EndRequest handlers.

  7. PostResolveRequestCache The request can’t be served from the cache, and the procedure continues. An HTTP handler corresponding to the requested URL is created at this point. If the requested resource is an .aspx page, an instance of a page class is created.

  8. MapRequestHandler The event is fired to determine the request handler.

  9. PostMapRequestHandler The event fires when the HTTP handler corresponding to the requested URL has been successfully created.

  10. AcquireRequestState The module that hooks up this event is willing to retrieve any state information for the request. A number of factors are relevant here: the handler must support session state in some form, and there must be a valid session ID.

  11. PostAcquireRequestState The state information (such as Application, Session) has been acquired.

  12. PreRequestHandlerExecute This event is fired immediately prior to executing the handler for a given request. The handler does its job and generates the output for the client.

  13. ExecuteRequestHandler The handler does its job and processes the request.

  14. PostRequestHandlerExecute This event is raised when the handler has generated the response text.

  15. ReleaseRequestState This event is raised when the handler releases its state information and prepares to shut down. This event is used by the session state module to update the dirty session state if necessary.

  16. PostReleaseRequestState The state, as modified by the page execution, has been persisted. Any relevant response filtering is done at this point. (I’ll say more about this topic later.)

  17. UpdateRequestCache The ASP.NET runtime determines whether the generated output, now also properly filtered by registered modules, should be cached to be reused with upcoming identical requests.

  18. PostUpdateRequestCache The page has been saved to the output cache if it was configured to do so.

  19. LogRequest The event indicates that the runtime is ready to log the results of the request. Logging is guaranteed to execute even if errors occur.

  20. PostLogRequest The request has been logged.

  21. EndRequest This event fires as the final step of the HTTP pipeline. Control passes back to the HttpRuntime object, which is responsible for the actual forwarding of the response to the client. At this point, the text has not been sent yet.

If an unhandled error occurs at any point during the processing, it is treated using the code (if any) associated with the Error event. As mentioned, events can be handled in HTTP modules as well as in global.asax.

Note

The Error event provides a centralized console for capturing any unhandled exception in order to recover gracefully or just to capture the state of the application and log it. By writing an HTTP module that just intercepts the Error event, you have a simple but terribly effective and reusable mechanism for error handling and logging. At the end of the day, this is the core of the engine of popular tools for ASP.NET error handling, logging, and reporting—ELMAH.

The global.asax File

The global.asax file is used by Web applications to handle some application-level events raised by the ASP.NET runtime or by registered HTTP modules. The global.asax file is optional. If it is missing, the ASP.NET runtime environment simply assumes you have no application or module event handlers defined. To be functional, the global.asax file must be located in the root directory of the application. Only one global.asax file per application is accepted. Any global.asax files placed in subdirectories are simply ignored. Note that Microsoft Visual Studio doesn’t list global.asax in the items you can add to the project if there already is one.

Compiling global.asax

When the application is started, global.asax, if present, is parsed into a source class and compiled. The resultant assembly is created in the temporary directory just as any other dynamically generated assembly would be. The following listing shows the skeleton of the C# code that ASP.NET generates for any global.asax file:

namespace ASP
{
    public class global_asax : System.Web.HttpApplication
    {
        //
        // The source code of the "global.asax" file is flushed
        // here verbatim. For this reason, the following code
        // in global.asax would generate a compile error.
        //     int i;
        //     i = 2;  // can't have statements outside methods
        //
    }
}

The class is named ASP.global_asax and is derived from the HttpApplication base class. In most cases, you deploy global.asax as a separate text file; however, you can also write it as a class and compile it either in a separate assembly or within your project’s assembly. The class source code must follow the outline shown earlier and, above all, must derive from HttpApplication. The assembly with the compiled version of global.asax must be deployed in the application’s Bin subdirectory.

Note, though, that even if you isolate the logic of the global.asax file in a precompiled assembly, you still need to have a (codeless) global.asax file that refers to the assembly, as shown in the following code:

<%@ Application Inherits="MyApp.Global" %>

You’ll learn more about the syntax of global.asax in the next section, “Syntax of global.asax.” With a precompiled global application file, you certainly don’t risk exposing your source code over the Web to malicious attacks. However, even if you leave it as source code, you’re somewhat safe.

The global.asax file, in fact, is configured so that any direct URL request for it is automatically rejected by Internet Information Services (IIS). In this way, external users cannot download or view the code it contains. The trick that enables this behavior is the following line of code, excerpted from machine.config:

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

ASP.NET registers with IIS to handle .asax resources, but then it processes those direct requests through the HttpForbiddenHandler HTTP handler. As a result, when a browser requests an .asax resource, an error message is displayed on the page, as shown in Figure 16-1.

Direct access to forbidden resources, such as *.asax files, results in a server error.

Figure 16-1. Direct access to forbidden resources, such as *.asax files, results in a server error.

When the global.asax file of a running application is modified, the ASP.NET runtime detects the change and prepares to shut down and restart the application. It waits until all pending requests are completed and then fires the Application_End event. When the next request from a browser arrives, ASP.NET reparses and recompiles the global.asax file, and again raises the Application_Start event.

Syntax of global.asax

A few elements determine the syntax of the global.asax file. They are application directives, code declaration blocks, server-side <object> tags, and static properties. These elements can be used in any order and number to compose a global.asax file.

Application Directives

The global.asax file supports three directives: @Application, @Import, and @Assembly. The @Import and @Assembly directives work as shown in Chapter 3. The @Import directive imports a namespace into an application; the @Assembly directive links an assembly to the application at compile time.

The @Application directive supports a few attributes: Description, Language, and Inherits. Description can contain any text you want to use to describe the behavior of the application. This text has only a documentation purpose and is blissfully ignored by the ASP.NET parser. Language indicates the language being used in the file. The Inherits attribute indicates a code-behind class for the application to inherit. It can be the name of any class derived from the HttpApplication class. The assembly that contains the class must be located in the Bin subdirectory of the application.

Code Declaration Blocks

A global.asax file can contain code wrapped by a <script> tag. Just as for pages, the <script> tag must have the runat attribute set to server. The language attribute indicates the language used throughout:

<script language="C#" runat="server">
    ...
</script>

If the language attribute is not specified, ASP.NET defaults to the language set in the configuration, which is Microsoft Visual Basic .NET. The source code can also be loaded from an external file, whose virtual path is set in the Src attribute. The location of the file is resolved using Server.MapPath—that is, starting under the physical root directory of the Web application.

<script language="C#" runat="server" src="somecode.aspx.cs" />

In this case, any other code in the declaration <script> block is ignored. Notice that ASP.NET enforces syntax rules on the <script> tag. The runat attribute is mandatory, and if the block has no content, the Src must be specified.

Server-Side <object> Tags

The server-side <object> tag lets you create new objects using a declarative syntax. The <object> tag can take three forms, as shown in the following lines of code, depending on the specified reference type:

<object id="..." runat="server" scope="..." class="..." />
<object id="..." runat="server" scope="..." progid="..." />
<object id="..." runat="server" scope="..." classid="..." />

In the first case, the object is identified by the name of the class and assembly that contains it. In the last two cases, the object to create is a COM object identified by the program identifier (progid) and the 128-bit CLSID, respectively. As one can easily guess, the classid, progid, and class attributes are mutually exclusive. If you use more than one within a single server-side <object> tag, a compile error is generated. Objects declared in this way are loaded when the application is started.

The scope attribute indicates the scope at which the object is declared. The allowable values are defined in Table 16-5. Unless otherwise specified, the server-side object is valid only within the boundaries of the HTTP pipeline that processes the current request. Other settings that increase the object’s lifetime are application and session.

Table 16-5. Feasible Scopes for Server-Side <object> Tags

Scope

Description

pipeline

Default setting, indicates the object is available only within the context of the current HTTP request

application

Indicates the object is added to the StaticObjects collection of the Application object and is shared among all pages in the application

session

Indicates the object is added to the StaticObjects collection of the Session object and is shared among all pages in the current session

Static Properties

If you define static properties in the global.asax file, they will be accessible for reading and writing by all pages in the application:

<script language="C#" runat="server">
    public static int Counter = 0;
</script>

The Counter property defined in the preceding code works like an item stored in Application—namely, it is globally visible across pages and sessions. Consider that concurrent access to Counter is not serialized; on the other hand, you have a strong-typed, direct global item whose access speed is much faster than retrieving the same piece of information from a generic collection such as Application.

To access the property from a page, you must use the ASP.global_asax qualifier, shown here:

Response.Write(ASP.global_asax.Counter.ToString());

If you don’t particularly like the ASP.global_asax prefix, you can alias it as long as you use C#. Add the following code to a C#-based page (or code-behind class) for which you need to access the globals:

using Globals = ASP.global_asax;

The preceding statement creates an alias for the ASP.global_asax class (or whatever name your global.asax class has). The alias—Globals in this sample code—can be used throughout your code wherever ASP.global_asax is accepted. In ASP.NET 4, however, you can also rely on the dynamic type.

The HttpContext Class

During the various steps of the request’s chain of execution, an object gets passed along from class to class—this object is the HttpContext object. HttpContext encapsulates all the information available about an individual HTTP request that ASP.NET is going to handle. The HttpContext class is instantiated by the HttpRuntime object while the request processing mechanism is being set up. Next, the object is flowed throughout the various stages of the request’s lifetime.

Important

Before I get into the details of HttpContext and other ASP.NET intrinsic objects, I should note that in ASP.NET 4 all these objects inherit from a base class. For example, HttpContext derives from HttpContextBase and HttpResponse extends the capabilities of HttpResponseBase. The reason is to make it easier to write unit tests to check the behavior of code-behind classes. By using base classes, you can more easily create mocks of intrinsic objects and inject them into the classes. In Chapter 15, you saw an approach to testability that will benefit from base classes for intrinsic objects. Note that the ASP.NET Cache is not included in the list of objects with a base class.

Properties of the HttpContext Class

Table 16-6 enumerates all the properties exposed by the HttpContext class. The class represents a single entry point for a number of intrinsic objects such as classic ASP intrinsics and ASP.NET-specific Cache and User objects.

Table 16-6. HttpContext Properties

Property

Description

AllErrors

Gets an array of Exception objects, each of which represents an error that occurred while processing the request.

Application

Gets an instance of the HttpApplicationState class, which contains the global and shared states of the application.

ApplicationInstance

Gets or sets the HttpApplication object for the current request. The actual type is the global.asax code-behind class. It makes a cast to access public properties and methods you might have defined in global.asax.

Cache

Gets the ASP.NET Cache object for the current request.

Current

Gets the HttpContext object for the current request.

CurrentHandler

Gets the handler for the request that is currently being executed by the application. It is a read-only property that returns the value stored in Handler.

CurrentNotification

Indicates which event in the request pipeline is currently processing the request. It works only if the application is running in integrated pipeline mode.

Error

Gets the first exception (if any) that has been raised while processing the current request.

Handler

Gets or sets the HTTP handler for the current request.

IsCustomErrorEnabled

Indicates whether custom error handling is enabled for the current request.

IsDebuggingEnabled

Indicates whether the current request is in debug mode.

IsPostNotification

Indicates whether the current request has been processed and whether we’re in the middle of a PostXxx stage. It works only if the application is running in integrated pipeline mode.

Items

Gets a name/value collection (hash table) that can be used to share custom data and objects between HTTP modules and HTTP handlers during the request lifetime.

PreviousHandler

Gets the last handler before the current request was executed.

Profile

Gets the object that represents the profile of the current user.

Request

Gets an instance of the HttpRequest class, which represents the current HTTP request.

Response

Gets an instance of the HttpResponse class, which sends HTTP response data to the client.

Server

Gets an instance of the HttpServerUtility class, which provides helper methods for processing Web requests.

Session

Gets an instance of the HttpSessionState class, which manages session-specific data.

SkipAuthorization

Gets or sets a Boolean value that specifies whether the URL-based authorization module will skip the authorization check for the current request. This is false by default. It is mostly used by authentication modules that need to redirect to a page that allows anonymous access.

Timestamp

Gets a DateTime object that represents the initial timestamp of the current request.

Trace

Gets the TraceContext object for the current response.

User

Gets or sets the IPrincipal object that represents the identity of the user making the request.

The Current property is a frequently used static member that returns the HttpContext object for the request being processed.

The Items property is a dictionary object—a hash table, to be exact—that can be used to share information between the modules and handlers involved with the particular request. By using this property, each custom HTTP module or handler can add its own information to the HttpContext object serving the request. The information stored in Items is ultimately made available to the page. The lifetime of this information is limited to the request.

Methods of the HttpContext Class

Table 16-7 lists the methods specific to the HttpContext class.

Table 16-7. HttpContext Methods

Method

Description

AddError

Adds an exception object to the AllErrors collection.

ClearError

Clears all errors for the current request.

GetAppConfig

Returns requested configuration information for the current application. The information is collected from machine.config and the application’s main web.config files. It is marked as obsolete in ASP.NET 4.0.

GetConfig

Returns requested configuration information for the current request. The information is collected at the level of the requested URL, taking into account any child web.config files defined in subdirectories. It is marked as obsolete in ASP.NET 4.0.

GetGlobalResourceObject

Loads a global resource.

GetLocalResourceObject

Loads a local, page-specific resource.

GetSection

Returns requested configuration information for the current request.

RemapHandler

Allows you to programmatically set the handler to serve the request. It must be invoked before the runtime reaches the MapRequestHandler stage. If the Handler property of HttpContext is not null at that stage, the runtime defaults to it.

RewritePath

Mostly for internal use; overwrites URL and the query string of the current Request object.

SetSessionStateBehavior

Allows you to programmatically set the expected behavior for the session state—either read-only, read-write, or no session. It must be called before the AcquireRequestState event fires.

Over time, the GetSection method has replaced GetConfig, which has been marked as obsolete and should not be used. If you have old code using GetConfig, just change the name of the method. The prototype is the same. Also, GetAppConfig is marked as obsolete in ASP.NET 4. It has been replaced by GetWebApplicationSection, a static member of the new WebConfigurationManager class. Also, in this case, no changes are required to be made to the prototype. Let’s spend a few more words to dig out some interesting characteristics of other methods of the HttpContext class.

URL Rewriting

The RewritePath method lets you change the URL of the current request on the fly, thus performing a sort of internal redirect. As a result, the displayed page is the one you set through RewritePath; the page shown in the address bar remains the originally requested one. The change of the final URL takes place on the server and, more importantly, within the context of the same call. RewritePath should be used carefully and mainly from within the global.asax file. If you use RewritePath in the context of a postback event, you can experience some view-state problems.

protected void Application_BeginRequest(Object sender, EventArgs e)
{
   var context = HttpContext.Current;
   var o = context.Request["id"];
   if (o != null)
   {
      var id = (Int32) o;
      var url = GetPageUrlFromId(id);
      context.RewritePath(url);
   }
}
protected String GetPageUrlFromId(Int32 id)
{
   // Return a full URL based on the input ID value.
   ...
}

The preceding code rewrites a URL such as page.aspx?id=1234 to a specific page whose real URL is read out of a database or a configuration file.

Note

In general, IIS-level URL rewriting (which was discussed in Chapter 2) is a better alternative. The newer and more general ASP.NET Routing is perhaps better suited for a more complex use case, but it can achieve the same result pretty easily.

Loading Resources Programmatically

In Chapter 7, we discussed expressions allowed in ASP.NET pages to bind control properties to embedded global or local resources. The $Resources and meta:resourcekey expressions for global and local resources, respectively, work only at design time. What if you need to generate text programmatically that embeds resource expressions, instead? Both the Page and HttpContext classes support a pair of programmatic methods to retrieve the content of resources embedded in the application.

GetGlobalResourceObject retrieves a global resource—that is, a resource defined in an .resx file located in the App_GlobalResources special folder. GetLocalResourceObject does the same for an .resx file located in the App_LocalResources special folder of a given page.

msg1.Text = (String) HttpContext.GetGlobalResourceObject(
     "Test", "MyString");
msg2.Text = (String) HttpContext.GetLocalResourceObject(
     "/MyApp/Samples/ResPage.aspx", "PageResource1.Title");

The first parameter you pass to GetGlobalResourceObject indicates the name of the .resx resource file without an extension; the second parameter is the name of the resource to retrieve. As for GetLocalResourceObject, the first argument indicates the virtual path of the page; the second is the name of the resource.

The Server Object

In the all-encompassing container represented by the HttpContext object, a few popular objects also find their place. Among them are Server, Request, and Response. They are old acquaintances for ASP developers and, indeed, they are feature-rich elements of the ASP.NET programming toolkit. The set of properties and methods still makes these objects a fundamental resource for developers. Let’s learn more about them, starting with the Server object.

The functionality of the ASP intrinsic Server object in ASP.NET is implemented by the HttpServerUtility class. An instance of the type is created when ASP.NET begins to process the request and is then stored as part of the request context. The bunch of helper methods that HttpServerUtility provides are publicly exposed to modules and handlers—including global.asax, pages, and Web services—through the Server property of the HttpContext object. In addition, to maintain ASP.NET coding as close as possible to the ASP programming style, several other commonly used ASP.NET objects also expose their own Server property. In this way, developers can use in the code, say, Server.MapPath without incurring compile errors.

Properties of the HttpServerUtility Class

This class provides two properties, named MachineName and ScriptTimeout. The MachineName property returns the machine name, whereas ScriptTimeout gets and sets the time in seconds that a request is allowed to be processed. This property accepts integers and defaults to 90 seconds; however, it is set to a virtually infinite value if the page runs with the attribute debug=true, as shown here:

this.Server.ScriptTimeout = 30000000;

The ScriptTimeout property is explicitly and automatically set in the constructor of the dynamically created class that represents the page.

Methods of the HttpServerUtility Class

Table 16-8 lists all methods exposed by the HttpServerUtility class. As you can see, they constitute a group of helper methods that come in handy at various stages of page execution. The class provides a couple of methods to create instances of COM components and a few others to deal with errors. Another group of methods relates to the decoding and encoding of content and URLs.

Table 16-8. Methods of the Server Object

Method

Description

ClearError

Clears the last exception that was thrown for the request.

CreateObject

Creates an instance of the specified COM object.

CreateObjectFromClsid

Creates an instance of the COM object identified by the specified CLSID. The class identifier is expressed as a string.

Execute

Passes control to the specified page for execution. The child page executes like a subroutine. The output can be retained in a writer object or automatically flushed in the parent response buffer.

GetLastError

Returns the last exception that was thrown.

HtmlDecode

Decodes a string that has been encoded to eliminate invalid HTML characters. For example, it translates &lt; into <.

HtmlEncode

Encodes a string to be displayed in a browser. For example, it encodes < into &lt;.

MapPath

Returns the physical path that corresponds to the specified virtual path on the Web server.

Transfer

Works as a kind of server-side redirect. It terminates the execution of the current page and passes control to the specified page. Unlike Execute, control is not passed back to the caller page.

UrlDecode

Decodes a string encoded for HTTP transmission to the server in a URL. The decoded string can be returned as a string or output to a writer.

UrlEncode

Encodes a string for HTTP transmission to a client in a URL. The encoded string can be returned as a string or output to a writer.

UrlPathEncode

Encodes only the path portion of a URL string, and returns the encoded string. This method leaves the query string content intact.

UrlTokenDecode

Converts a URL string token, which encodes binary data as base 64 digits, to its equivalent byte array representation.

UrlTokenEncode

Encodes a byte array into its equivalent string representation using base 64 digits, which is usable for transmission on the URL.

HTML and URL encoding are ways of encoding characters to ensure that the transmitted text is not misunderstood by the receiving browser. HTML encoding, in particular, replaces <, >, &, and quotes with equivalent HTML entities such as &lt;, &gt;, &amp;, and &quot;. It also encodes blanks, punctuation characters, and in general, all characters not allowed in an HTML stream. On the other hand, URL encoding is aimed at fixing the text transmitted in URL strings. In URL encoding, the same critical characters are replaced with different character entities than in HTML encoding.

Embedding Another Page’s Results

The Execute method allows you to consider an external page as a subroutine. When the execution flow reaches the Server.Execute call, control is passed to the specified page. The execution of the current page is suspended, and the external page is spawned. The response text generated by the child execution is captured and processed according to the particular overload of Execute that has been used. Table 16-9 lists the overloads of the Execute method.

Table 16-9. Overloads of the Execute Method

Overload

Description

Execute(string);

You pass the URL of the page, and the response text is automatically embedded in the main page.

Execute(string, TextWriter);

The response text is accumulated in the specified text writer.

Execute(string, bool);

The same description as for previous item, except that you can choose whether to preserve the QueryString and Form collections. True is the default setting.

Execute(IHttpHandler, TextWriter, bool);

You indicate the HTTP handler to transfer the current request to. The response is captured by the text writer.

Execute(string, TextWriter, bool);

The response text is captured by the specified text writer, and the QueryString and Form collections are either preserved or not preserved, as specified.

Note that if a TextWriter object is specified, the response text of the child execution is accumulated into the writer object so that the main page output can be used later at will. Here’s some sample code:

void Page_Load(Object sender, EventArgs e)
{
    var builder = new StringBuilder();
    builder.Append("<b>Response generated before
                    Execute is called</b><hr/>");

    // Capture child content
    var writer = new StringWriter();
    Server.Execute("child.aspx", writer);
    builder.Append(writer.ToString());

    builder.Append("<hr/><b>Response generated after
                   the call to Execute.</b>");

    Label1.Text = builder.ToString();
}

It’s interesting to look at the internal implementation of the Execute method. Both the main and child pages are run by the same HttpApplication object as if they were the same request. What happens within the folds of Execute is a sort of context switch. First, the method obtains an HTTP handler from the application factory to serve the new request. The original handler of the main request is cached and replaced with the new handler. The spawned page inherits the context of the parent; when this step is finished, any modification made to Session or Application is immediately visible to the main page.

The handler switching makes the whole operation extremely fast, as there’s no need to create a new object to serve the request. When the child page returns, the original handler is restored. The execution of the main page continues from the point at which it was stopped, but it uses the context inherited from the child page.

Caution

ASP.NET directly calls the handler indicated by the Execute method without reapplying any authentication and authorization logic. If your security policy requires clients to have proper authorization to access the resource, the application should force reauthorization. You can force reauthorization by using the Response.Redirect method instead of Execute. When Redirect is called, the browser places a new request in the system, which will be authenticated and authorized as usual by IIS and ASP.NET. As an alternative, you can verify whether the user has permission to call the page by defining roles and checking the user’s role before the application calls the Execute method.

Server-Side Redirection

The Transfer method differs from the Execute method in that it terminates the current page after executing the specified page. The new page runs as if it was the originally requested one. The Transfer method has the following overloads:

public void Transfer(String);
public void Transfer(String, Boolean);
public void Transfer(IHttpHandler, Boolean);

The string parameter indicates the destination URL. The Boolean parameter indicates what to do with regard to the QueryString and Form collections. If the parameter is true, the collections are preserved; otherwise, they are cleared and made unavailable to the destination page (which is the recommended approach). You can also directly indicate the HTTP handler to invoke, with the same security issues that were mentioned for Execute.

All the code that might be following the call to Transfer in the main page is never executed. In the end, Transfer is just a page redirect method. However, it is particularly efficient for two reasons. First, no roundtrip to the client is requested, as is the case, for example, with Response.Redirect. Second, the same HttpApplication that was serving the caller request is reused, thus limiting the impact on the ASP.NET infrastructure.

The HttpResponse Object

In ASP.NET, the HTTP response information is encapsulated in the HttpResponse class. An instance of the class is created when the HTTP pipeline is set up to serve the request. The instance is then linked to the HttpContext object associated with the request and exposed via the Response property. The HttpResponse class defines methods and properties to manipulate the text that will be sent to the browser. Although user-defined ASP.NET code never needs to use the HttpResponse constructor, looking at it is still useful to get the gist of the class:

public HttpResponse(TextWriter writer);

As you can see, the constructor takes a writer object, which will then be used to accumulate the response text. All calls made to Response.Write (and similar output methods) are resolved in terms of internal calls to the specified writer object.

Properties of the HttpResponse Class

All properties of the class are grouped and described in Table 16-10. You set a few of these properties to configure key fields on the HTTP response packet, such as content type, character set, page expiration, and status code.

Table 16-10. HttpResponse Properties

Property

Description

Buffer

Indicates whether the response text should be buffered and sent only at the end of the request. This property is deprecated and provided only for backward compatibility with classic ASP. ASP.NET applications should instead use BufferOutput.

BufferOutput

Gets or sets a Boolean value that indicates whether response buffering is enabled. The default is true.

Cache

Gets the caching policy set for the page. The caching policy is an HttpCachePolicy object that can be used to set the cache-specific HTTP headers for the current response.

CacheControl

Sets the Cache-Control HTTP header. Acceptable values are Public, Private, or No-Cache. The property is deprecated in favor of Cache.

Charset

Gets or sets a string for the HTTP character set of the output stream. If set to null, it suppresses the Content-Type header.

ContentEncoding

Gets or sets an object of type Encoding for the character encoding of the output stream.

ContentType

Gets or sets the string that represents the Multipurpose Internet Mail Extensions (MIME) type of the output stream. The default value is text/html.

Cookies

Gets a collection (HttpCookieCollection) object that contains instances of the HttpCookie class generated on the server. All the cookies in the collection will be transmitted to the client through the set-cookie HTTP header.

Expires

Gets or sets the number of minutes before a page cached on a browser expires. Provided for compatibility with ASP, the property is deprecated in favor of Cache.

ExpiresAbsolute

Gets or sets the absolute date and time at which the page expires in the browser cache. Provided for compatibility with ASP, the property is deprecated in favor of Cache.

Filter

Gets or sets a filter Stream object through which all HTTP output is directed.

HeaderEncoding

Gets or sets an Encoding object that represents the encoding for the current header output stream.

Headers

Gets the collection of response headers. The property is supported only in integrated pipeline mode.

IsClientConnected

Indicates whether the client is still connected.

IsRequestBeingRedirected

Indicates whether the request is being redirected.

Output

Gets the writer object used to send text out.

OutputStream

Gets the Stream object used to output binary data to the response stream.

RedirectLocation

Gets or a sets a string for the value of the Location header.

Status

Sets the string returned to the client describing the status of the response. Provided for compatibility with ASP, the property is deprecated in favor of StatusDescription.

StatusCode

Gets or sets an integer value for the HTTP status code of the output returned to the client. The default value is 200.

SubStatusCode

Indicates the sub status code of the response. The property is supported only in integrated pipeline mode.

StatusDescription

Gets or sets the HTTP status string, which is a description of the overall status of the response returned to the client. The default value is OK.

SuppressContent

Gets or sets a Boolean value that indicates whether HTTP content should be sent to the client. This is set to false by default; if it is set to true, only headers are sent.

TrySkipIisCustomErrors

Boolean property, indicates whether or not custom errors set at the IIS level should by ignored by ASP.NET. The default value when running in Integrated mode is false. The property is effective only for applications hosted in IIS 7 or later.

Let’s find out more about cache and expiration properties.

Setting the Response Cache Policy

The response object has three properties dedicated to controlling the ability of the page being sent to the browser to be cached. The Expires and ExpiresAbsolute properties define relative and absolute times, respectively, at which the page cached on the client expires and is no longer used by the browser to serve a user request. In fact, if the user navigates to a currently cached page, the cached version is displayed and no roundtrip occurs to the server. A third property somehow related to page caching is CacheControl. The property sets a particular HTTP header—the Cache-Control header. The Cache-Control header controls how a document is to be cached across the network. These properties represent the old-fashioned programming style and exist mostly for compatibility with classic ASP applications.

In ASP.NET, all caching capabilities are grouped in the HttpCachePolicy class. With regard to page caching, the class has a double role. It provides methods for both setting cache-specific HTTP headers and controlling the ASP.NET page output cache. In this chapter, we’re mostly interested in the HTTP headers, and we’ll keep page output caching warm for Chapter 18.

To set the visibility of a page in a client cache, use the SetCacheability method of the HttpCachePolicy class. To set an expiration time, use the SetExpires method, which takes for input an absolute DateTime object. Finally, to set a lifetime for the cached page, pass to SetExpires the current time plus the desired interval.

Note

In the case of conflicting cache policies, ASP.NET maintains the most restrictive settings. For example, if a page contains two controls that set the Cache-Control header to public and private, the most restrictive policy will be used. In this case, Cache-Control: Private is what will be sent to the client.

Setting an Output Filter

In ASP.NET, a new component makes its debut—the response filter. A response filter is a Stream-derived object associated with the HttpResponse object. It monitors and filters any output being generated by the page. If you set the Filter property with the instance of a class derived from Stream, all output being written to the underlying HTTP writer first passes through your output filter.

The custom filter, if any, is invoked during the HttpResponse’s Flush method before the actual text is flushed to the client. An output filter is useful for applying the final touches to the markup, and it is sometimes used to compact or fix the markup generated by controls.

Building a response filter is a matter of creating a new stream class and overriding some of the methods. The class should have a constructor that accepts a Stream object. In light of this, a response filter class is more a wrapper stream class than a purely inherited stream class. If you simply try to set Response.Filter with a new instance of, say, MemoryStream or FileStream, an exception is thrown.

The following listing shows how to create a stream class that works as a response filter. For simplicity, the class inherits from MemoryStream. You might want to make it inherit from Stream, but in this case you need to override (because they are abstract) a number of methods, such as CanRead, CanWrite, CanSeek, and Read. The class converts lowercase characters to uppercase ones.

public class MyFilterStream : MemoryStream
{
    private Stream m_Stream;

    public MyFilterStream(Stream filterStream)
    {
        m_Stream = filterStream;
    }

    // The Write method actually does the filtering
    public override void Write(byte[] buffer, int offset, int count)
    {
        // Grab the output as a string
        string buf = UTF8Encoding.UTF8.GetString(buffer, offset, count);

        // Apply some changes
        // Change lowercase chars to uppercase
        buf = buf.ToUpper();

        // Write the resulting string back to the response stream
        byte[] data = UTF8Encoding.UTF8.GetBytes(buf.ToString());
        m_Stream.Write(data, 0, data.Length);
    }
}

Use the following code to associate this output filter with the Response.Filter property. Here’s a sample page:

void Page_Load(object sender, EventArgs e)
{
    Response.Filter = new MyFilterStream(Response.Filter);
}

Response filters provide an interesting opportunity for developers to build more powerful applications, but I caution you to be careful when considering this option. As the sample demonstrates, changing the case of the entire output is not a smart move. If done without care, the change ends up affecting the view state and the internal script code, both of which consist of case-sensitive text, seriously compromising the functionality of the page. Second, filters must be activated on a per-page basis. If you need to filter all the pages in a Web site, you’re better off writing an HTTP module.

Methods of the HttpResponse Class

Table 16-11 lists all the methods defined on the HttpResponse class.

Table 16-11. HttpResponse Methods

Method

Description

AddCacheDependency

Adds an array of cache dependencies to make the cached page output invalid if any dependency gets broken. In the array, you can have any class that inherits from CacheDependency.

AddCacheItemDependencies

Adds an array of strings representing names of items in the ASP.NET Cache. When any of the specified items vary, the cached page output becomes invalid.

AddCacheItemDependency

Description is the same as for the previous item, except that AddCacheItemDependency adds a single cache item name.

AddFileDependencies

Adds a group of file names to the collection of file names on which the current page is dependent. When any of the files are modified, the cached output of the current page is deemed invalid.

AddFileDependency

Adds a single file name to the collection of file names on which the current page is dependent. If the file is modified, the cached output of the current page becomes invalid.

AddHeader

Adds an HTTP header to the output stream. It is provided for compatibility with previous versions of ASP. In ASP.NET, you should use AppendHeader.

AppendCookie

Adds an HTTP cookie to the cookie collection.

AppendHeader

Adds an HTTP header to the output stream.

AppendToLog

Adds custom log information to the IIS log file.

ApplyAppPathModifier

Adds a session ID to the specified virtual path, and returns the result. It is mostly used with cookieless sessions to construct absolute HREFs for hyperlinks.

BinaryWrite

Writes binary characters to the HTTP output stream. It is subject to failures with very large files. (See the references to this method later in the chapter.)

Clear

Clears all content output from the buffer stream.

ClearContent

Calls into Clear.

ClearHeaders

Clears all headers from the buffer stream.

Close

Closes the socket connection with the client.

DisableKernelCache

Disables kernel caching for the current response. If kernel caching is not supported, the method has no effect.

End

Sends all buffered text to the client, stops execution, and raises the end event for the request.

Flush

Sends all currently buffered output to the client.

Pics

Appends a PICS-Label HTTP header to the output. PICS stands for Platform for Internet Content Selection and is a World Wide Web Consortium (W3C) standard for rating pages. Any string is acceptable as long as it doesn’t exceed 255 characters.

Redirect

Redirects a client to a new URL. It needs a roundtrip. The browser receives an HTTP 302 status code, meaning that the resource has been temporarily moved.

RedirectPermanent

Redirects a client to a new URL. It needs a roundtrip. The browser receives an HTTP 301 status code, meaning that the resource has been permanently moved to a new location.

RedirectToRoute

Redirects a client to a URL specified as a route. The method works if Web Forms routing is used to specify routes.

RemoveOutputCacheItem

A static method that takes a file system path and removes from the cache all cached items associated with the specified path.

SetCookie

Updates an existing cookie in the cookie collection.

TransmitFile

Just like BinaryWrite and WriteFile, it writes the specified file directly to the output stream. You can safely use TransmitFile regardless of the size of the file that you want to transmit.

Write

Writes content to the underlying output stream. The method can write a string, a single character, or an array of characters, as well as an object. In this case, though, what gets written is the output of the object’s ToString method.

WriteFile

Writes the specified file (or a portion of it) directly to the output stream. The file can be identified with its path or a Win32 handle (an IntPtr object). It is subject to failures with very large files. (See the references to this method later in the chapter.)

WriteSubstitution

Allows fragments of a page to be substituted and sent to the output cache. (We’ll cover this method in more detail in Chapter 18.)

Output Caching Features

The HttpResponse class has several methods to make the page response it represents dependent on files or cache item changes. The methods AddFileDependency and AddCacheItemDependency (and their versions that handle multiple dependencies) make the page response invalid when the specified file or files or cached item or items are modified.

This is a simple form of programmatic page output caching, not as powerful as the API that we’ll examine in Chapter 18, but still worth a look. The API discussed in Chapter 18 is superior because it allows you to control how the page response is cached, assigning also the cached output a duration and perhaps a location.

The method AddCacheDependency completes the offering, as it gives you the possibility to make the page response dependent on any dependency object available to your application, including custom dependency objects. See Chapter 18 for more details on custom dependency objects.

Large File Transmission

As you can see, there are three methods for writing potentially large chunks of data down to the output stream: BinaryWrite, WriteFile, and TransmitFile. Of the three methods, TransmitFile is the most stable and reliable, although you won’t notice any significant difference for most files.

Both the WriteFile and BinaryWrite methods seem perfect for streaming binary data down to the client. However, both can put the Web server memory under pressure if called to work on very large files. Why? It’s because both methods load the entire data block (the contents of the file or the byte array) into the Web server’s memory. For large files, this can cause severe problems that can culminate in the recycling of the ASP.NET process. The TransmitFile method is designed to elegantly work around the problem. It sends output directly from a file to the ASP.NET ISAPI extension and then down to the client, without passing a humongous string to the ISAPI extension.

Note

Although TransmitFile makes large file downloads more stable than ever and fixes the problem of recycling, it is far from being a full solution to the problem of tracking and resuming large file downloads. For example, if a download fails, for whatever reason, TransmitFile can start it again only from the beginning. The article found at the following Web site discusses a better approach to the problem: http://www.devx.com/dotnet/Article/22533.

The HttpRequest Object

The HttpRequest object groups all the information contained in the HTTP packet that represents the incoming Web request. The contents of the various HTTP headers, the query string, or the form’s input fields, path, and URL information are organized in a series of collections and other ad hoc objects for easy and effective programmatic access. The HttpRequest object is populated as soon as ASP.NET begins working on a Web request, and it’s made available through the Request property of HttpContext.

HttpRequest exposes a fair number of properties and is one of the objects that has been more significantly enriched in the transition from ASP to ASP.NET.

Properties of the HttpRequest Class

The class properties can be categorized into three groups based on the type of information they contain: the type of the request, client data, and connection.

Information About the Request

Table 16-12 lists the properties that define the type of request being issued.

Table 16-12. Properties Describing the Request Type

Property

Description

AcceptTypes

Gets an array of strings denoting the list of MIME types supported by the client for the specified request.

AnonymousID

Indicates the ID of the anonymous user, if any. The identity refers to the string generated by the AnonymousIdentification module and has nothing to do with the identity of the IIS anonymous user.

Browser

Gets an HttpBrowserCapabilities object that contains information about the capabilities of the client’s browser.

ContentEncoding

Gets or sets an Encoding object that represents the client’s character set. If specified, this property overrides the ASP.NET default encoding.

ContentLength

Gets the length in bytes of the content sent by the client.

ContentType

Gets or sets the MIME content type of the incoming request.

CurrentExecutionFilePath

Gets the current virtual path of the request even when the client is redirected to another page via Execute or Transfer. The FilePath property, on the other hand, always returns the path to the originally requested page.

FilePath

Gets the virtual path of the current request. The path doesn’t change in cases of server-side page redirection.

HttpMethod

Gets a string that denotes the HTTP method used for the request. Values are GET, POST, or HEAD.

RequestType

Gets or sets a string that denotes the HTTP command used to issue the request. It can be GET or POST.

TotalBytes

Gets the total number of bytes in the input stream. This property differs from ContentLength in that it also includes headers.

UserAgent

Gets a string that identifies the browser. This property gets the raw content of the user agent header.

The anonymous ID is usually transmitted through a cookie (whose default name is .ASPXANONYMOUS) and serves the purpose of giving an identity to nonauthenticated users, mainly for user profile functions. The anonymous ID is a GUID and is transmitted as clear text. It doesn’t play any relevant role with authentication and security; it is merely a way to track nonregistered users as they move around the site. (See Chapter 7 for profiles and Chapter 19, for user authentication.)

Initially, CurrentExecutionFilePath and FilePath share the same content—the requested URL. However, in cases of server-side redirects, the value of CurrentExecutionFilePath is automatically updated. You should check CurrentExecutionFilePath for up-to-date information about the target URL.

The HttpBrowserCapabilities object groups in a single place values that identify a fair number of browser capabilities, including support for ActiveX controls, scripting languages, frames, cookies, and more. When the request arrives, the user agent information is used to identify the requesting browser and an instance of the HttpBrowserCapabilities class is created and populated with browser-specific information. The information is in no way dynamically set by the browser; instead, it is retrieved from an offline server-side repository.

Information from the Client

Table 16-13 lists the HttpRequest properties that expose the client data that ASP.NET pages might want to use for server-side processing. The following table includes, for example, cookies, forms, and query string collections.

Table 16-13. Properties Describing the Client Data

Property

Description

ClientCertificate

Gets an HttpClientCertificate object with information on the client’s security certificate settings, if any. The certificate object wraps up information such as number, validity, and issuer of the certificate.

Cookies

Gets a collection representing all cookies sent by the client. A cookie is identified by the HttpCookie object.

Files

Gets a collection of client-uploaded files. The property requires the HTTP Content-Type header to be set to multipart/form-data.

Filter

Gets or sets a Stream-based object through which all HTTP input passes when received. The filtered input is anything read via InputStream.

Form

Gets a name-value collection filled with the values of the input fields in the form posted. The collection is populated when the Content-Type header is either application/x-www-form-urlencoded or multipart/form-data.

Headers

Gets a name-value collection filled with all the header values in the request.

InputStream

Gets a Stream object representing the contents of the incoming HTTP content body.

Params

Gets a name-value collection that is a union of four other similar collections: QueryString, Form, ServerVariables, and Cookies.

QueryString

Gets a name-value collection containing all the query string variables sent by the client.

ServerVariables

Gets a name-value collection filled with a collection of Web server–defined variables.

UserHostAddress

Gets the Internet Protocol (IP) address of the remote client.

UserHostName

Gets the Domain Name System (DNS) name of the remote client.

UserLanguages

Gets an array of strings denoting the list of the languages accepted by the client for the specified request. The languages are read from the Accept-Language header.

The Params collection combines four different but homogeneous collections—QueryString, Form, ServerVariables, and Cookies—and it replicates the information contained in each of them. The collections are added in the following order: QueryString, Form, Cookies, and finally ServerVariables.

Information About the Connection

Table 16-14 lists the properties that relate to the open connection.

Table 16-14. Properties Describing the Connection

Property

Description

ApplicationPath

Gets the virtual path of the current application.

IsAuthenticated

Indicates whether or not the user has been authenticated.

IsLocal

Indicates if it is a local request.

IsSecureConnection

Indicates whether the connection is taking place over a Secure Sockets Layer (SSL) using HTTPS.

LogonUserIdentity

Gets an object representing the Windows identity of the current user as logged at the IIS gate.

Path

Gets the virtual path of the current request.

PathInfo

Gets additional path information for the requested resource, if any. The property returns any text that follows the URL.

PhysicalApplicationPath

Gets the file system path of the current application’s root directory.

PhysicalPath

Gets the physical file system path corresponding to the requested URL.

RawUrl

Gets the raw URL of the current request.

Url

Gets the Uri object that represents the URL of the current request.

UrlReferrer

Gets the Uri object that represents the URL from which the current request originated.

The Uri class provides an object representation of a Uniform Resource Identifier (URI)—a unique name for a resource available on the Internet. The Uri class provides easy access to the parts of the URI as well as properties and methods for checking host, loopback, ports, and DNS.

The server variables set in the ServerVariables collection are decided by the run-time environment that processes the request. The information packed in the collection is, for the most part, excerpted from the HTTP worker request object; another part contains Web server–specific information. The ServerVariables collection is just a friendly name/value model to expose that information.

Methods of the HttpRequest Class

Table 16-15 lists all methods exposed by the HttpRequest class.

Table 16-15. HttpRequest Methods

Method

Description

BinaryRead

Performs a binary read from the current input stream. The method lets you specify the number of bytes to read and returns an array of bytes. The method is provided for compatibility with ASP. ASP.NET applications should read from the stream associated with the InputStream property.

MapImageCoordinates

Maps an incoming image-field form parameter to x/y coordinate values.

MapPath

Maps the specified virtual path to a physical path on the Web server.

SaveAs

Saves the current request to a file disk with or without headers. This method is especially useful for debugging.

ValidateInput

Performs a quick, nonexhaustive check to find potentially dangerous input data in the request.

Saving the Request to Disk

The SaveAs method lets you create a file to store the entire content of the HTTP request. Note that the storage medium can only be a disk file; no stream or writer can be used. Because ASP.NET by default isn’t granted write permissions, this method causes an access-denied exception unless you implement ad hoc measures. Granting the ASP.NET account full control over the file to be created (or over the whole folder) is one of the possible ways to successfully use the SaveAs method. The following listing shows possible content that SaveAs writes to disk:

GET /MyApp/Samples/Ch14/Misc/TestFilter.aspx HTTP/1.1
Connection: Keep-Alive
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: it,en-us;q=0.5
Cookie: .ASPXANONYMOUS=AGzHqyVAyAEkAAAAO ... MWE3YZreWoYt-jkSc_RwU169brWNTIw1
Host: localhost:1066
User-Agent: ...

UA-CPU: x86

If the intercepted request is a POST, you’ll find posted values at the bottom of the string.

Validating Client Input

A golden rule of Web security claims that all user input is evil and should always be filtered and sanitized before use. The @Page directive has an attribute—ValidateRequest—that automatically blocks postbacks that contain potentially dangerous data. This feature is not the silver bullet of Web input security, but it helps detect possible problems. From a general security perspective, you’re better off replacing the automatic input validation with a strong, application-specific validation layer.

The automatic input validation feature—ValidateRequest—is enabled by default and implemented via a call to the HttpRequest’s ValidationInput method. ValidateInput can be called by your code if the validation feature is not enabled. Request validation works by checking all input data against a hard-coded list of potentially dangerous data. The contents of the collections QueryString, Form, and Cookies are checked during request validation.

Summary

In this chapter, we covered some basic objects that are the foundation of ASP.NET programming: Server, Response, Request, and others. An ASP.NET application is represented by an instance of the HttpApplication class properly configured by the contents of the global.asax file. And both the HttpApplication class and the global.asax file found their space in this chapter too.

While discussing the interface of the objects that generate the context of an HTTP request, we reviewed in detail some specific programming issues, such as server-side page redirection and the setup of response filters. In the next chapter, we’ll discuss an important topic related to Web applications and ASP.NET—state management. Fundamentally, Web applications are stateless, but ASP.NET provides various mechanisms for maintaining application state and caching pages.

In ASP.NET 4, all intrinsic objects (except Cache) have been derived from a new base class to give developers better chances to be able to write testable Web pages.

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

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