HTTP HAndlers

download HTTP HAndlers

of 14

Transcript of HTTP HAndlers

  • 8/8/2019 HTTP HAndlers

    1/14

    HTTP Handlers and HTTP Modules in ASP.NETIntroduction

    In the Internet world, Web servers serve resources that have been put on the Internet and provide otherservices like security, logging, etc.

    At the beginning of the Internet era, clients' needs were very limited; .htm files were often satisfactory. As

    time passed, however, clients' requirements extended beyond the functionality contained in .htm files orstatic files.

    Developers needed a way to extend or complement the functionality of Web servers. Web server vendorsdevised different solutions, but they all followed a common theme: "Plug some component into the Web

    server". All Web server complement technologies allowed developers to create and plug in components

    for enhancing Web server functionality. Microsoft came up with ISAPI (Internet Server API); Netscapecame up with NSAPI (Netscape Server API), etc.

    ISAPI is an important technology that allows us to enhance the capabilities of an ISAPI-compliant Web

    server (IIS is an ISAPI-compliant Web server). The following components serve this purpose:

    ISAPI Extensions

    ISAPI Filters

    ISAPI extensions are implemented by using Win32 DLLs. You can think of an ISAPI extension as a

    normal application. ISAPI extensions are the target of http requests. That means you must call them to

    activate them. For example, the following URL calls the store.dll ISAPI extension and passes two valuesto it:

    http://www.myownwebsite.com/Store.dll?sitename=15seconds&location=USA

    Think of an ISAPI filter as just that: a filter. It sits between your Web server and the client. Every time aclient makes a request to the server, it passes through the filter.

    Clients do not specifically target the filter in their requests, rather, clients simply send requests to the Webserver, and then the Web server passes that request to the interested filters.

    Filters can then modify the request, perform some logging operations, etc.

    It was very difficult to implement these components because of the complexities involved. One had to use

    C/C++ to develop these components, and for many, development in C/C++ is a pain.

    So what does ASP.NET offer to harness this functionality? ASP.NET offers HttpHandlers andHttpModules.

    Before going into the details of these components, it is worth looking at the flow of http requests as it

    passes through the HTTP modules and HTTP handlers.

    Setting up the Sample Applications

    I have created the following C# projects, which demonstrate different components of the application.

    NewHandler (HTTP handler)

  • 8/8/2019 HTTP HAndlers

    2/14

    Webapp (Demonstrates HTTP handler)

    SecurityModules (HTTP module)

    Webapp2 (Demonstrated HTTP module)

    To install the applications:

    Extract all the code from the attached zip file.

    Create two virtual directories named webapp and webapp2; point these directories to the actualphysical folders for the Webapp and Webapp2 web applications.

    Copy the Newhandler.dll file from the NewHandler project into the bin directory of webapp web

    application.

    Copy the SecurityModules.dll file from the SecurityModules project into the bin directory of

    webapp2 web application.

    ASP.NET Request Processing

    ASP.NET request processing is based on a pipeline model in which ASP.NET passes http requests to all

    the modules in the pipeline. Each module receives the http request and has full control over it. The module

    can play with the request in any way it sees fit. Once the request passes through all of the HTTP modules,it is eventually served by an HTTP handler. The HTTP handler performs some processing on it, and the

    result again passes through the HTTP modules in the pipeline.

    The following figure describes this flow.

    Notice that during the processing of an http request, only one HTTP handler will be called, whereas morethan one HTTP modules can be called.

    Http Handlers

    HTTP handlers are the .NET components that implement the System.Web.IHttpHandler interface. Anyclass that implements the IHttpHandler interface can act as a target for the incoming HTTP requests.

    HTTP handlers are somewhat similar to ISAPI extensions. One difference between HTTP handlers and

    ISAPI extensions is that HTTP handlers can be called directly by using their file name in the URL, similar

    to ISAPI extensions.

    http://www.15seconds.com/files/020417.ziphttp://www.15seconds.com/files/020417.zip
  • 8/8/2019 HTTP HAndlers

    3/14

    HTTP handlers implement the following methods.

    Method Name Description

    ProcessRequestThis method is actually the heart of all http handlers. This method is called to process http

    requests.

    IsReusable

    This property is called to determine whether this instance of http handler can be reused for

    fulfilling another requests of the same type. HTTP handlers can return either true or false inorder to specify whether they can be reused.

    These classes can be mapped to http requests by using the web.config or machine.config file. Once that is

    done, ASP.NET will instantiate http handler whenever the corresponding request comes in. We will see

    how to specify all of these details in web.config and/or machine.config files.

    ASP.NET also supports the creation of http handlers by means of the IHttpHandlerFactory interface.ASP.NET provides the capability of routing http requests to an object of the class that implements the

    IHttpHandlerFactory interface. Here, ASP.NET utilizes the Factory design pattern. This pattern provides

    an interface for creating families of related objects without specifying their concrete classes. In simple

    terms, you can consider such a class as a factory that creates http handler objects depending on theparameters passed to it. We don't have to specify a particular http handler class to instantiate; http handler

    factory takes care of it. The benefit of this is if in the future the implementation of the object thatimplements the IHttpHandler interface changes, the consuming client is not affected as long as the

    interface remains the same.

    These are following methods in IHttpHandlerFactory interface:

    Method Name Description

    GetHandlerThis method is responsible for creating the appropriate handler and returns the referenceout to the calling code (the ASP.NET runtime). Handler object returned by this method

    should implement the IHttpHandler interface.

    ReleaseHandler

    This method is responsible for releasing the http handler once request processing is

    complete. The implementation of the factory decides what it should do. Factoryimplementation can either actually destroy the instance or return it to a pool for future

    requests.

    Registering HTTP Handlers and HTTP Handler Factories in Configuration Files

    ASP.NET maintains its configuration information in the following configuration files:

    machine.config web.config

    machine.config file contains the configuration settings that apply to all the Web applications installed onthat box.

    web.config file is specific to each Web application. Each Web application can have its own web.config

    file. Any sub directory of a Web application may have its own web.config file; this allows them to

    override the settings imposed by the parent directories.

  • 8/8/2019 HTTP HAndlers

    4/14

    We can use and nodes for adding HTTP handlers to our Web applications. In fact

    the handlers are listed with nodes in between and nodes. Here is a

    generic example of adding an HTTP handler:

    In the above XML,

    The verb attribute specifies the HTTP verbs supported by the handler. If the handler supports all of

    the HTTP verbs, simply use "*", otherwise list the supported verbs in a comma separated list. So ifyour handler supports only HTTP GET and POST, then verb attribute will be "GET, POST".

    The path attribute specifies the path or wildcard specification of the files for which this handler

    will be invoked. For example, if you want your handler to be called only when test.xyz file isrequested, then the path attribute will contain "test.xyz"; similarly if you want your handler called

    for any file having .xyz extension, the path attribute will contain "*.xyz".

    The type attribute specifies the actual type of the handler or handler factory in the form of acombination of namespace, class name and assembly name. ASP.NET runtime first searches the

    assembly DLL in the application's bin directory and then searches in the Global Assembly Cache

    (GAC).

    Use of HTTP Handlers by the ASP.NET Runtime

    Believe it or not, ASP.NET uses HTTP handlers for implementing a lot of its own functionality. ASP.NETuses handlers for processing .aspx, .asmx, .soap and other ASP.NET files.

    The following is the snippet from the machine.config file:

    . . . . . .

    . . . . . .

    You can see in the above configuration that all the requests for .aspx files are processed by theSystem.Web.UI.PageHandlerFactory class. Similarly all the requests for .config and other files, which

    should not be directly accessible to the clients, are handled by the System.Web.HttpForbiddenHandler

    class. As you might have already guessed, this class simply returns an error to the client stating that thesekinds of files are not served.

    Implementing HTTP Handlers

    Now we will see how to implement an HTTP handler. So what should our new handler do? Well, as I

    stated above, handlers are mostly used for adding new functionalities to Web servers; therefore, we will

  • 8/8/2019 HTTP HAndlers

    5/14

    create a handler that handles new types of files, files that have a .15seconds extension. Once we

    implement this handler and register it in the web.config file of our Web application, all requests for .

    15seconds files will be handled by this new handler.

    You might be thinking about the use of such a handler. Well, what if you want to introduce a new kind ofserver scripting language or dynamic server file such as asp, aspx? You can write your own handler for

    this. Similarly, what will you do if you want to run Java servlets, JSPs and other server side Java

    components on IIS? One way of doing this is to install some ISAPI extension like Allaire or MacromediaJrun. Or you can write your own HTTP handler. Although it is a difficult task for third-party vendors like

    Allaire and Macromedia, it is a very attractive option because their HTTP handlers will have access to all

    the new functionalities exposed by the ASP.NET runtime.

    Steps involved in implementing our HTTP handler are as follows:

    1. Write a class which implements IHttpHandler interface

    2. Register this handler in web.config or machine.config file.

    3. Map the file extension (.15seconds) to ASP.NET ISAPI extension DLL (aspnet_isapi.dll) in

    Internet Services Manager.

    Step1

    Create a new C# Class Library project in Visual Studio.NET and name it "MyHandler". Visual

    Studio.NET will automatically add a class named "Class1.cs" into the project. Rename it "NewHandler";open this class in the code window and change the class name and constructor name to "NewHandler".

    The following is the code for the NewHandler class.

    using System;

    using System.Web;

    namespace MyHandler{

    /// /// Summary description for NewHandler.

    ///

    public class NewHandler : IHttpHandler{

    public NewHandler()

    {

    //// TODO: Add constructor logic here

    //}

    #region Implementation of IHttpHandler

    public void ProcessRequest(System.Web.HttpContext context){

    HttpResponse objResponse = context.Response ;

    objResponse.Write("Hello 15Seconds Reader ") ;

    objResponse.Write("") ;}

  • 8/8/2019 HTTP HAndlers

    6/14

    public bool IsReusable

    {

    get{

    return true;

    }}

    #endregion}

    }

    As you can see in the ProcessRequest method, the HTTP handler has access to all ASP.NET intrinsic

    objects passed to it in its parameter through the System.Web.HttpContext object. Implementing theProcessRequest method is simply extracting the HttpResponse object from the context object and then

    sending some HTML out to the client. Similarly, IsReusable returns true to designate that this handler can

    be reused for processing the other HTTP requests.

    Let's compile it and place it in the bin directory of the webapp virtual directory.

    Step 2

    Register this handler by adding the following text in the web.config file:

    Step 3

    Since we are creating a handler for handling files of a new extension, we also need to tell IIS about thisextension and map it to ASP.NET. If we don't perform this step and try to access the Hello.15seconds file,

    IIS will simply return the file rather than pass it to ASP.NET runtime. As a consequence, the HTTP

    handler will not be called.

    Launch the Internet Services Manager tool, right click on Default Web Site, select Properties, goto Home Directory tab and press Configuration button. This will popup Application

    Configuration dialog. ClickAdd button and fill the Executable field with the path to the aspnet_isapi.dll

    file and fill .15seconds in the Extension field. Leave the other fields as is; the dialog box should look as

    follows:

    Close the Application Configuration and Default Web Site Properties dialog boxes by pressing

    the OKbutton.

    Now we are good to go. Launch Internet Explorer and go to the following url:

    http://localhost/webapp/hello.15seconds

  • 8/8/2019 HTTP HAndlers

    7/14

    You should see the following page:

    Session State in HTTP Handlers

    Maintaining session state is one of the most common tasks that Web applications perform. HTTP handlers

    also need to have access to the session state. But session state is not enabled by default for HTTP handlers.In order to read and/or write session data, HTTP handlers are required to implement one of the following

    interfaces:

    IRequiresSessionState

    IReadOnlySessionState.

    An HTTP handler should implement the IRequiresSessionState interface when it requires read-write

    access to the session data. If a handler only needs read access to session data, then it should only

    implement the IReadOnlySessionState interface.

    Both of these interfaces are just marker interfaces and do not contain any methods. So if we want toenable session state for our NewHandler handler, then declare the NewHandler class as followed:

    public class NewHandler : IHttpHandler, IRequiresSessionState

    HTTP Modules

    HTTP modules are .NET components that implement the System.Web.IHttpModule interface. These

    components plug themselves into the ASP.NET request processing pipeline by registering themselves forcertain events. Whenever those events occur, ASP.NET invokes the interested HTTP modules so that the

    modules can play with the request.

    An HTTP module is supposed to implement the following methods of the IHttpModule interface:

    MethodName

    Description

    InitThis method allows an HTTP module to register its event handlers to the events in the

    HttpApplication object.

    DisposeThis method gives HTTP module an opportunity to perform any clean up before the object

    gets garbage collected.

    An HTTP module can register for the following events exposed by the System.Web.HttpApplication

    object.

  • 8/8/2019 HTTP HAndlers

    8/14

    Event Name Description

    AcquireRequestStateThis event is raised when ASP.NET runtime is ready to acquire the Session

    state of the current HTTP request.

    AuthenticateRequestThis event is raised when ASP.NET runtime is ready to authenticate the

    identity of the user.

    AuthorizeRequestThis event is raised when ASP.NET runtime is ready to authorize the user for

    the resources user is trying to access.BeginRequest This event is raised when ASP.NET runtime receives a new HTTP request.

    DisposedThis event is raised when ASP.NET completes the processing of HTTP

    request.

    EndRequest This event is raised just before sending the response content to the client.

    ErrorThis event is raised when an unhandled exception occurs during the

    processing of HTTP request.

    PostRequestHandlerExecute This event is raised just after HTTP handler finishes execution.

    PreRequestHandlerExecute

    This event is raised just before ASP.NET begins executing a handler for the

    HTTP request. After this event, ASP.NET will forward the request to theappropriate HTTP handler.

    PreSendRequestContent

    This event is raised just before ASP.NET sends the response contents to the

    client. This event allows us to change the contents before it gets delivered to

    the client. We can use this event to add the contents, which are common in allpages, to the page output. For example, a common menu, header or footer.

    PreSendRequestHeaders

    This event is raised just before ASP.NET sends the HTTP response headers to

    the client. This event allows us to change the headers before they get delivered

    to the client. We can use this event to add cookies and custom data intoheaders.

    ReleaseRequestState This event is raised after ASP.NET finishes executing all request handlers.

    ResolveRequestCache

    This event is raised to determine whether the request can be fulfilled by

    returning the contents from the Output Cache. This depends on how the

    Output Caching has been setup for your web application.

    UpdateRequestCache

    This event is raised when ASP.NET has completed processing the current

    HTTP request and the output contents are ready to be added to the Output

    Cache. This depends on how the Output Caching has been setup for your Web

    application.

    Apart from these events, there are four more events that we can use. We can hook up to these events byimplementing the methods in the global.asax file of our Web application.

    These events are as follows:

    Application_OnStart

    This event is raised when the very first request arrives to the Web application.

    Application_OnEndThis event is raised just before the application is going to terminate.

    Session_OnStart

    This event is raised for the very first request of the user's session.

  • 8/8/2019 HTTP HAndlers

    9/14

    Session_OnEnd

    This event is raised when the session is abandoned or expired.

    Registering HTTP Modules in Configuration Files

    Once an HTTP module is built and copied into the bin directory of our Web application or copied into theGlobal Assembly Cache, then we will register it in either the web.config or machine.config file.

    We can use and nodes for adding HTTP modules to our Web applications. In fact

    the modules are listed by using nodes in between and nodes.

    Since configuration settings are inheritable, the child directories inherit configuration settings of the parent

    directory. As a consequence, child directories might inherit some unwanted HTTP modules as part of theparent configuration; therefore, we need a way to remove those unwanted modules. We can use the

    node for this.

    If we want to remove all of the inherited HTTP modules from our application, we can use the node.

    The following is a generic example of adding an HTTP module:

    The following is a generic example of removing an HTTP module from your application.

    In the above XML,

    The type attribute specifies the actual type of the HTTP module in the form of class and assemblyname.

    The name attribute specifies the friendly name for the module. This is the name that will be usedby other applications for identifying the HTTP module.

    Use of HTTP Modules by the ASP.NET Runtime

    ASP.NET runtime uses HTTP modules for implementing some special features. The following snippet

    from the machine.config file shows the HTTP modules installed by the ASP.NET runtime.

  • 8/8/2019 HTTP HAndlers

    10/14

    All of the above HTTP modules are used by ASP.NET to provide services like authentication and

    authorization, session management and output caching. Since these modules have been registered inmachine.config file, these modules are automatically available to all of the Web applications.

    Implementing an HTTP Module for Providing Security Services

    Now we will implement an HTTP module that provides security services for our Web application. Our

    HTTP module will basically provide a custom authentication service. It will receive authentication

    credentials in HTTP request and will determine whether those credentials are valid. If yes, what roles arethe user associated with? Through the User.Identity object, it will associate those roles that are accessible

    to our Web application pages to the user's identity.

    Following is the code of our HTTP module.

    using System;using System.Web;

    using System.Security.Principal;

    namespace SecurityModules{

    ///

    /// Summary description for Class1.

    ///

    public class CustomAuthenticationModule : IHttpModule

    {

    public CustomAuthenticationModule(){

    }public void Init(HttpApplication r_objApplication)

    {

    // Register our event handler with Application object.

    r_objApplication.AuthenticateRequest +=new EventHandler(this.AuthenticateRequest) ;

    }

    public void Dispose()

    {// Left blank because we dont have to do anything.}

    private void AuthenticateRequest(object r_objSender,EventArgs r_objEventArgs)

    {

    // Authenticate user credentials, and find out user roles.

    1. HttpApplication objApp = (HttpApplication) r_objSender ;2. HttpContext objContext = (HttpContext) objApp.Context ;

    3. if ( (objApp.Request["userid"] == null) ||

  • 8/8/2019 HTTP HAndlers

    11/14

    4. (objApp.Request["password"] == null) )

    5. {

    6. objContext.Response.Write("Credentials not provided") ;7. objContext.Response.End() ;

    8. }

    9. string userid = "" ;

    10. userid = objApp.Request["userid"].ToString() ;11. string password = "" ;

    12. password = objApp.Request["password"].ToString() ;

    13. string[] strRoles ;

    14. strRoles = AuthenticateAndGetRoles(userid, password) ;15. if ((strRoles == null) || (strRoles.GetLength(0) == 0))

    16. {

    17. objContext.Response.Write("We are sorry but we could notfind this user id and password in our database") ;

    18. objApp.CompleteRequest() ;

    19. }

    20. GenericIdentity objIdentity = new GenericIdentity(userid,

    "CustomAuthentication") ;

    21. objContext.User = new GenericPrincipal(objIdentity, strRoles) ;}

    private string[] AuthenticateAndGetRoles(string r_strUserID,string r_strPassword)

    {

    string[] strRoles = null ;

    if ((r_strUserID.Equals("Steve")) &&(r_strPassword.Equals("15seconds")))

    {

    strRoles = new String[1] ;strRoles[0] = "Administrator" ;

    }

    else if ((r_strUserID.Equals("Mansoor")) &&(r_strPassword.Equals("mas")))

    {

    strRoles = new string[1] ;strRoles[0] = "User" ;

    }

    return strRoles ;}

    }

    }

    Let's explore the code.

    We start with the Init function. This function plugs in our handler for the AuthenticateRequest event into

    the Application object's event handlers list. This will cause the Application object to call this method

    whenever the AuthenticationRequest event is raised.

  • 8/8/2019 HTTP HAndlers

    12/14

    Once our HTTP module is initialized, its AuthenticateRequest method will be called for authenticating

    client requests. AuthenticateRequest method is the heart of the security/authentication mechanism. In that

    function:

    Line 1 and Line 2 extract the HttpApplication and HttpContext objects. Line 3 through Line 7 checkswhether any of the userid or password is not provided to us. If this is the case, error is displayed and the

    request processing is terminated.

    Line 9 through Line 12 extract the user id and password from the HttpRequest object.

    Line 14 calls a helper function, named AuthenticateAndGetRoles. This function basically performs theauthentication and determines the user role. This has been hard-coded and only two users are allowed, but

    we can generalize this method and add code for interacting with some user database to retrieve user roles.

    Line 16 through Line 19 checks whether the user has any role assigned to it. If this is not the case that

    means the credentials passed to us could not be verified; therefore, these credentials are not valid. So, anerror message is sent to the client and the request is completed.

    Line 20 and Line 21 are very important because these lines actually inform the ASP.NET HTTP runtimeabout the identity of the logged-in user. Once these lines are successfully executed, our aspx pages will be

    able to access this information by using the User object.

    Now let's see this authentication mechanism in action. Currently we are only allowing the following users

    to log in to our system:

    User id = Steve, Password = 15seconds, Role = Administrator

    User id = Mansoor, Password = mas, Role = User

    Note that user id and password are case-sensitive.

    First try logging-in without providing credentials. Go to http://localhost/webapp2/index.aspx and you

    should see the following message.

    Now try logging-in with the user id "Steve" and password "15seconds". Go to

    http://localhost/webapp2/index.aspx?userid=Steve&password=15seconds and you should see the

    following welcome message.

  • 8/8/2019 HTTP HAndlers

    13/14

    Now try to log-in with the user id "Mansoor" and password "15seconds". Go to

    http://localhost/webapp2/index.aspx?userid=Mansoor&password=mas and you should see the following

    welcome page.

    Now try to log-in with the wrong combination of user id and password. Go to

    http://localhost/webapp2/index.aspx?userid=Mansoor&password=xyz and you should see the followingerror message.

    This shows our security module in action. You can generalize this security module by using database-

    access code in the AuthenticateAndGetRoles method.

    For all of this to work, we have to perform some changes in our web.config file. First of all, since we areusing our own custom authentication, we don't need any other authentication mechanism. To specify this,

    change the node in web.config file of webapp2 to look like this:

    Similarly, don't allow anonymous users to our Web site. Add the following to web.config file:

  • 8/8/2019 HTTP HAndlers

    14/14

    Users should at least have anonymous access to the file that they will use for providing credentials. Usethe following configuration setting in the web.config file for specifying index.aspx as the only

    anonymously accessible file:

    Conclusion

    As you might have realized with HTTP handlers and modules, ASP.NET has put a lot of power in thehands of developers. Plug your own components into the ASP.NET request processing pipeline and enjoy

    the benefits.