Once the context for the request is created, the HttpRuntime class sets up an ASP.NET application object to carry out the request. 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 1 lists the properties defined for the class.
Table 1. HttpApplication Properties
|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.|
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. (We’ll return to global.asax in a moment.)
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 .NET Framework defines a number of standard modules, as
listed in Table 2. Custom modules can be defined too.
Table 2. ASP.NET Modules
|AnonymousIdentification||Assigns anonymous users a fake identity. Not installed in ASP.NET 1.x.|
|FileAuthorization||Verifies that the remote user has 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. Not installed in ASP.NET 1.x.|
|RoleManager||Provides session-state services for the application. Not installed in ASP.NET 1.x.|
|ScriptModule||Used to implement page methods in AJAX pages. Not installed in ASP.NET 2.0.|
|SessionState||Provides session-state services for the application.|
|UrlAuthorization||Provides URL-based authorization services to access specified resources.|
|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. The modules listed in machine.config are available to all applications. By creating a proper web.config file, you can also create an application-specific list of modules. (Configuration is covered in Programming Microsoft ASP.NET 2.0 Applications: Advanced Topics.)
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 3.
Table 3. HttpApplication Operational Methods
|CompleteRequest||Sets an internal flag that causes ASP.NET to skip all successive steps in the pipeline and directly execute EndRequest. Mostly useful to HTTP modules.|
|Dispose||Overridable method, cleans up the instance variables of all registered modules once the request has been served. At this time, Request, Response, Session, and Application are no longer available.|
method, provides a way to set output caching based on a custom string
for all pages in the application. |
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.
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 14-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 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 4. HttpApplication Events
|AcquireRequestState, PostAcquireRequestState||Occurs when the handler that will actually serve the request acquires the state information associated with the request. The post event is not available in ASP.NET 1.x.|
|AuthenticateRequest, PostAuthenticateRequest||Occurs when a security module has established the identity of the user. The post event is not available in ASP.NET 1.x.|
|AuthorizeRequest, PostAuthorizeRequest||Occurs when a security module has verified user authorization. The post event is not available in ASP.NET 1.x.|
|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.|
|PostMapRequestHandler||Occurs when the HTTP handler to serve the request has been found. The event is not available in ASP.NET 1.x.|
|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. The post event is not available in ASP.NET 1.x.|
|ResolveRequestCache, PostResolveRequestCache||Occurs when the ASP.NET runtime resolves the request through the output cache. The post event is not available in ASP.NET 1.x.|
when the ASP.NET runtime stores the response of the current request in
the output cache to be used to serve subsequent requests. The post event is not available in ASP.NET 1.x.|
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 14-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 14-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.
Application events are fired in the following sequence:
BeginRequest The ASP.NET HTTP pipeline begins to work on the request. This event reaches the application after Application_Start.
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.
PostAuthenticateRequest The request has been authenticated. All the information available is stored in the HttpContext’s User property.
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.
PostAuthorizeRequest The request has been authorized.
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.
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.
PostMapRequestHandler The event fires when the HTTP handler corresponding to the requested URL has been successfully created.
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.
PostAcquireRequestState The state information (such as Application, Session) has been acquired.
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
PostRequestHandlerExecute This event is raised when the handler has generated the response text.
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.
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.)
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.
PostUpdateRequestCache The page has been saved to the output cache if it was configured to do so.
EndRequest This event fires as the final step of the HTTP pipeline. The 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.
Another pair of events can occur during the request, but in a nondeterministic order. They are PreSendRequestHeaders and PreSendRequestContent. The PreSendRequestHeaders event informs the HttpApplication object in charge of the request that HTTP headers are about to be sent. The event normally fires after EndRequest
but not always. For example, if buffering is turned off, the event gets
fired as soon as some content is going to be sent to the client.
Finally, with the PreSendRequestContent event, the HttpApplication
object in charge of the request learns that the response body is about
to be sent. Speaking of nondeterministic application events, it must be
said that a third nondeterministic event is, of course, Error.