Friday, February 8, 2008

HttpHandler in ASP.NET

Sometimes as ASP.NET developers we might have come across situations where we had to implement some custom security to files, of type doc, pdf, excel, jpg etc. I also had the same prob, in my case it was restricting access to jpg files. The reason for this was that the jpg files were graphs and these graphs contained sensitive business data which were not to be shared freely. The files had to be restricted not only based on the user’s role but also based on their login id. So how can I achieve this in asp.net? My problem had an easy solution, by making use of the location tag in web.config file I could give restricted access to the folder which contained graph images based on the user’s role or id. The sample tag is shown below.

But this solution wont work in my case, the reason being the charts are generated on the fly by the system based on dynamic data retrieved from the database and the security is also dynamic and can change often. The users of the system are allowed to apply security based on thier preference. Some images can have role based and some can have id based security. It will be disastrous to ask the customer to modify the web.config file manually and that also for each and every graph image generated. Any syntax error can take the whole site down. So what was the other solution?

The logic to check what kind of access a user has was successfully completed. But our problem was to restrict user’ from directly accessing the jpg images. As we all know if the user saves the jpg image url and pastes the same in the browser’ address bar he can very well view the image. We had to prevent the user from accessing images by directly pasting the url in the address bar of the browser. Even if he pastes the link he should be directed to the login page and should go through the normal authentication process and if he has rights to view the image then he should be able to view the image. So, how to achieve this? Any request to any jpg images in a particular folder should be processed by asp.net. Then after much research we found the solution, this can be achieved using HttpHandler.

What is HttpHandler?

Each and every extensions like aspx, asmx etc are processed by different HttpHandlers in asp.net. All aspx page requests are handled by the ASP.NET Page Handler (PageHandlerFactory) class, all asmx i.e. web services are handled by Web Service Handler(WebServiceHandlerFactory) class. HttpHander is a build in process which takes care of processing requests based on their extension (type) and produce output. In the case of .aspx files the ASP.NET Page Handler processes the request and converts the whole page into html tags and sends back to the browser. I think the story upto this is enough and everyone will be waiting for the main implementation. To implement HttpHandler you should do three things.

1. Extend the IHttpHandler interface and implement the same in your project.
2. Register the file extension using iis filters.
3. Create a web.config file having httpHandler tag and place the file in the directory where you want the images to be handled.

1. Extend the IHttpHandler interface and implement the same in your project.

The first step is to extend the IHttpHandler interface which will process the jpg extensions. IHttpHandler interface has one method and one property namely "ProcessRequest" and “IsReusable" respectively. The ProcessRequest method is the one where you have to implement your image processing logic. The code below shows a sample implementation.

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public class ImageHandler : IHttpHandler
{
    public ImageHandler()
    {
    }
    /* The overridden method to handle requests for jpg images.*/
    public void ProcessRequest(HttpContext     theContext)
    {
        ProcessGraphRequest(theContext);
    }
    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}

As you can see from the above code we are invoking another user defined function called “ProcessGraphRequest” where we have the logic for checking image access based on the user’s privileges. Inside the function if the logic evaluates and says the user has got rights to view the graph we will implement the following code. The logic evaluates and stores the result in a boolean variable called “hasGraphAccess”.

private void ProcessImageRequest(HttpContext theContext)
{
  /*Logic to ascertain whether the user has access to graph files or not goes here*/
    if (hasGraphAccess)//Boolean variable to check image access.
    {
        theContext.Response.WriteFile            (theContext.Request.PhysicalPath);
    }
    else
    {
        theContext.Response.Write("Sorry you don’t have access to view the image.");
    }
}

2. Register the file extension using iis filters.

Once the HTTPHandler class is implemented the next step is to register the file extension. Open IIS (type inetmgr in run/command window) and navigate to the virtual directory where you want to implement your custom HttpHandler class. Right click and open the properties window. Click on the “configuration” button in the “Virtual Directory” tab as shown in the figure below.

In the “Mappings” tab of the “Application configuration” window click the “Add” button.

In the “Add/Edit Application Extension Mapping” pop up window enter the extension, in this case “jpg”, in the “Extension” textbox. In the “Executable” text box paste the path for the aspnet_isappi.dll which processes the request for aspx, asmx etc. Check “All Verbs” radio button which means you are asking the aspnet_isappi.dll to process all the request irrespective of the method of their post back i.e. get, post etc. The screenshot with all the details filled is shown below.

3. web.config having the extension mapping.

In this step there is not much to do, one has to create a web.config file using any text editor and put the following lines of xml statement in the web.config and save it in the folder where you want to provide the security.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.web>
        <httpHandlers>
            <add verb="*" path="*.jpg" type="HttpHandlerWebsite.ImageHandler, App_Code"/>
        </httpHandlers>
    </system.web>
</configuration>

The explanation for the various httpHandler attributes is as follows

Attribute
Explanation
E.g.
verb What type of request you want to process i.e. POST, GET, PUT etc. You can enter a comma separated value (verb=”GET,POST”) or simply type “*” which means process all types of request. verb="GET,POST” OR verb="*”
Path The path attribute can contain a single url (will directly point to a file) or some wildcard string. path="*.jpg”
type The class name with full namespace specification and the assembly where to look for the HTTPHandler class. The value of the type attribute will be a comma separated one having the class name with namespace and the assembly name separated by a comma. type=”HttpHandlerWebsite.ImageHandler, App_Code

In case of .net 1.1 the above web.config will change to the following

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.web>
        <httpHandlers>
            <add verb="*" path="*.jpg" type="HttpHandlerWebsite.ImageHandler, HttpHandlerWebsite"/>
        </httpHandlers>
    </system.web>
</configuration>

The reason for this is that in .NET 2.0 and above versions all ASP.NET related files are compiled and put into appcode.dll file where as in .NET 1.1 it is clubbed into a dll having the same name as that of the ASP.NET solution/website.

Know more

Sandeep

24 comments:

  1. thx very much for this Post , i think it is very useful

    ReplyDelete
  2. Hi Eskandarani,
    Nice to hear that the was useful. Thats the aim of my blog, to be useful to someone.

    ReplyDelete
  3. Hi sandeep first off than q very much for your article, it's really helped me a lot .But i am little bit confused to implementing this Class file in my application can you please tell me how to incorporate this class with my application and how can i call this methods in my applications.

    ReplyDelete
  4. Hi Ramakishore,
    By class if you mean the HTTPHandler then the blog tells you all the steps required to implement the handler. You need to create a class which implements the IHTTPHandler interface, once that is done map the extension in IIS and finally add the HTTPHandler section in web.config file. Hope this clears your doubt, if not revert back.

    ReplyDelete
  5. Hi Sandeep,
    Thanks for your reply.I have implemented HTTP Handler class by using class library and i used that ddl in my application.
    and i have register the .gif extension in IIS also.
    Now i am able to restrict user to access images by typing url.But i am unable show the images for authenticated user.can u please tell me what is the reason behind..?

    ReplyDelete
  6. Hi Ramakishore,
    Please put a breakpoint in the ProcessRequest method of the HTTPHandler class and just do a debug. Hope you would have written the following code "contextObject.Response.WriteFile (contextObject.Request.PhysicalPath);". contextObject is the parameter in the ProcessRequest method. Also try clearing the response before writing the previous code. As there is no specific error it is very difficuilt to give solution without seeing the debug info.

    ReplyDelete
  7. Hi Sandeep,

    If you don't mine can u give me your email or contact number please .It is very urgent requirement for me.

    ReplyDelete
  8. Hi Ramakishore,
    My email id is sndppr@gmail.com.

    ReplyDelete
  9. Hi sandeep,

    I sent you an email please have look and reply to that mail.

    ReplyDelete
  10. Hi Chakri,
    I didn't get any email, can u check whether there is any spelling mistake in the email. Please resend the mail.

    Regards,
    Sandeep

    ReplyDelete
  11. Hi sandeep,
    Thank you very much for your reply,i sent you an email to sndppr@gmail.com.
    My mail id :ram.gandi@invensis.net
    Subject:Rama kishore -Restricting image access
    please check the mail and reply me ASAP.

    ReplyDelete
  12. Hi Sandeep,

    Nice blog, it has been very helpful.

    Any idea how I can make it restrict all files and not just .jpg? I do not fancy adding every extension to IIS.

    Thanks,
    Phi

    ReplyDelete
  13. I have not tried this, but I think .* would do the trick in IIS. But in that case if I am not wrong all the requests will be redirected to the custom HttpHandler. So be careful when you do something like this. Let me do some more R&D and will let you know more about this.

    ReplyDelete
  14. Dear Sandeep,
    Is it possible to totally bypass IIS management and do every thing from Web.config. I dont have access to my web server on internet so I am interested if this can be done from my ASP.net web programming itself.
    -Sudipto
    email: sudiptojahar2000@yahoo.com

    ReplyDelete
  15. Hi Sudipto,
    No, as far as I know its not possible. The filters in IIS decide to which process they need to transfer the request for further process. Another thing which you can do is you can make use of VBScript to registers these filters which again needs IIS access. Everything ends with IIS. Here are few links which will tell you how to make use of Scripting to access various IIS properties.
    http://msdn.microsoft.com/en-us/library/ms524830
    http://msdn.microsoft.com/en-us/library/ms525344

    And last resort is to send a mail to the IIS admin asking him to add filters to your website.

    ReplyDelete
  16. Hi Sandeep,

    Thanks for the helpful blog. I am new to web services. And am developing a web service wrapper to receive SOAP message over HTTP using 3rd party services. I added the web reference but the 3rd party service contains ProcessRequest interface. How do I use the service interface and how do I access the service methods?

    Any help will be appreciated,

    - Sleek

    ReplyDelete
  17. Hi Sleek,
    When you add a web service reference the system creates proxy classes for your service and just by using the proxy class you can access the web service methods. Normally Visual Studio adds reference to the proxy class if not you can add it manually. Also if you want to use the interface you need to make use of the concrete class which is implementing the interface. That I think once you add the proxy reference you will be able to find out.

    ReplyDelete
  18. Thanks for the response Sandeep. But how do I invoke the service methods using the processrequest interface within the service file (.asmx). The service methods i.e getAcctInfo() is only visible in test link (.aspx) and not within .asmx file.

    ReplyDelete
  19. Hi Sleek,
    I am sorry but I am not able to understand the scenario. Could you send me a detailed mail @ sndppr@gmail.com.

    ReplyDelete
  20. Under ASP.NET 4.0 and IIS7, it's no longer necessary to make any changes to IIS to implement HTTP handlers for random file types. This makes it perfect for websites running on a shared hosting account. I just published an article about this at http://www.blackbeltcoder.com/Articles/asp/writing-a-custom-http-handler-in-asp-net.

    ReplyDelete
  21. Hi Sandeep,
    First of all thanks for the post.But still i have a doubt regarding using ImageHandler class like where should i create this class in my project as i have used it in business folder and also done setting in iis and also made web.config file in image folder but still i am able to access all the images through typing path on browser.

    ReplyDelete
  22. Thanks Jonathan. It will be very helpful for people.

    ReplyDelete
  23. Hi Suneta,
    Which version of .NET are you using? Also which version of IIS are you using? It doesn't matter where you place your class as long you give correct class and dll name in web.config.

    ReplyDelete
  24. Hi Sandeep,
    I got a compilation error "hasGraphAcces" doesn't exists in the in current context, can u plz help me out.

    Thanks

    ReplyDelete

Please provide your valuable comments.