A common source of confusion when working with the ASP.NET platform is the difference between modules and handlers, so it is important I explain the role of each component before digging into the details of how handlers work.
The best way to understand each component is within the scope of the request life cycle. As I explained in Chapter 4, modules have two roles in request handling. They can be used flor diagnosis and debugging, or they can provide services used by other components. The modules I created in Chapter 4 fall into the diagnosis category: They added fragments of HTML to the response that provided insight into how the request was processed. By contrast, most of the built-in modules that come with ASP.NET provide services, such as caching, security, or the management of state data. As I explained in Chapter 1, these are the services that you consume within MVC framework controllers and views, as shown in Figure 5-2.
This figure is a refinement of one I showed you in Chapter 1, expanded to show more details about the ASP. NET components and request life cycle. As the figure illustrates, modules are instantiated at the start of the request handling process, and they set up services that are consumed through the ASP.NET context objects by the MVC framework controller and view in order to generate the response that will be sent to the client.
In Figure 5-1, I have shown the MVC framework programmer's view of the controller and view, but, as you may have guessed, the MVC functionality is integrated into the ASP.NET platform through a handler, as shown in Figure 5-3.
The first thing to notice is that there are multiple modules for each request but only one handler. The reason I am being so emphatic about the relationship between these components is because I want to be clear about they mesh with the request life-cycle events: The modules are created as soon as the request life cycle begins, but the selection and creation of the handler are built right into the life cycle, as shown in Figure 5-4.
The MapRequestHandler event is triggered before the ASP.NET platform locates the handler that will generate the content for the request, the process for which I describe in the "Creating a Handler" section later in this chapter. The PostMapRequestHandler event is triggered once the handler has been identified and instantiated. However, the handler isn't asked to generate the content until the PreRequestHandlerExecute event is triggered, which means that modules have an opportunity to respond to the handler selection and provide services that are unique to that handler, as shown in the figure. You'll see how this all works in the "Targeting a Specific Handler" section later in this chapter. (Modules can also override the handler selection process, as described in Chapter 6.)
Understanding Handlers
Handlers are classes that implement the System.Web.IHttpHandler interface, which defines the two methods that I have described in Table 5-3.
Name
|
Description
|
---|---|
ProcessRequest (context)
|
This method is called when the ASP.NET framework wants the handler to generate a response for a request. The parameter is an HttpContext object, which provides access to details of the request.
|
IsReusable
|
This property tells the ASP.NET framework whether the handler can be used to handle further requests. If the property returns false, then the ASP.NET framework will create new instances for each request. In most situations, returning a value of true doesn't mean that handlers will be reused unless you implement a custom handler factory, which I describe in the "Custom Handler Factories" section of this chapter.
|
The ProcessRequest method is passed an HttpContext object, which can be used to inspect the request and the state of the application through the properties I described in Chapter 3.
Handlers can generate any kind of content that can be delivered over HTTP, and the ASP.NET platform does not impose any constraints on how the content is created. ASP.NET includes a set of default handlers that support the Web Forms, the MVC framework, SignalR, and Web API technology stacks, but custom handlers can be used to support new kinds of applications or data.
Handlers and the Life-Cycle Events
In Figure 5-3, I explained that handler selection and content generation are part of the request life cycle, but I describe the significant events from the perspective of modules. Table 5-4 describes the key life-cycle events from the perspective of the handler.
Name
|
Description
|
---|---|
MapRequestHandler
PostMapRequestHandler |
MapRequestHandler is triggered when the ASP.NET framework wants to locate a handler for the request. A new instance of the handler will be created unless an existing instance declares it can be reused. The PostMapRequestHandler event is triggered once the handler has been selected.
|
PreRequestHandlerExecute
PostRequestHandlerExecute |
These events are triggered immediately before and after the call to the handler ProcessRequest method.
|
The life cycle of a handler is interwoven with the request and module life cycles. This may seem over complicated, but it provides for flexible interactions between handlers and modules (or the global application class if that's where you have defined your event handlers). All of this will start to make more sense as you see some examples of handlers and the way they can be used.
The MapRequestHandler and PostMapRequestHandler events are different from the other pairs of events in the life cycle. Normally, the first event in a pair is a request for a module to provide a service, and the second event signals that phase of the life cycle is complete. So, for example, the AcquireRequestState event is a request for modules that handle state data to associate data with the request, and thePostAcquireRequestState event signals that all of the modules that handled the first event have finished responding.
The MapRequestHandler event isn't an invitation for a module to supply a handler for a request; that's a task that ASP.NET handles itself, and the event just signals that the selection is about to be made (a process I describe in the next section). The PostMapRequestHandler event signals that the handler has been selected, which allows modules to respond to the handler choice—generally by setting up services or data specific to the chosen handler.
The handler's ProcessRequest method is called between the PreRequestHandlerExecute and PostRequestHandlerExecute events. Modules can use these events as the last opportunity to manipulate the context objects before the content is generated by the handler and the first opportunity to manipulate the response once the handler is done.