Wednesday, September 28, 2005

Custom HTTP Handlers

Your application can be configured to use any class that implements IHttpHandler interface to process the incoming request.

For this

1. you define a class that implements IHttpHandler interface

2. Define the ProcessRequest and IsReusable methods of the IHttpHandler interface

3. Tell the worker process (through web.config file) to use your class, instead of a default one, to process the request and form the Response.



Step 3 can be eliminated If you name the file with .ashx extension instead of .cs.

That is, if you write an ashx file that defines a class which implements IHttpHandler, you need not update either web.config or IIS settings.

Following is a very simple example. [This doesn't hold true for handlers in custom controls or other applications. See example B]

Example A:

Single-file model:

Test.ashx

<%@ webhandler language="C#" class="Hyland.Applications.Web.Client.Test"%>



using System;

using System.Web;



namespace Hyland.Applications.Web.Client

{

     public class Test : System.Web.IHttpHandler

     {

          public bool IsReusable

          {

              
get { return true; }

          }



          public void ProcessRequest(HttpContext hc)

          {

              
hc.Response.ContentType = "text/html";

              
hc.Response.Write("<B>SOME TEXT</B>");

          }

     }

}




Code-behind model:


Test.ashx

<%@ webhandler language="C#" class="Hyland.Applications.Web.Client.Test" CodeBehind="Test.ashx.cs"%>



Test.ashx.cs

using System;

using System.Web;



namespace Hyland.Applications.Web.Client

{

     public class Test : System.Web.IHttpHandler

     {

          public bool IsReusable

          {

              
get { return true; }

          }



          public void ProcessRequest(HttpContext hc)

          {

                 
hc.Response.ContentType = "text/html";

                 
hc.Response.Write("<B>SOME TEXT</B>");

          }

     }

}



In either case:

Browser

http://localhost/AppNet/Test.ashx



[No web.config settings need to be updated, no IIS setttings need to be updated]



[Note: Class attribute is REQUIRED which specifies the class that implements IHttpHandler interface and can handle the current request. If Class attribute is not specified, "Directive is missing a class attribute" exception occurs.]



Example B:

Suppose you have a Custom Control that has embedded images in its assembly.

Suppose the Control outputs some HTML as follows...

<img src="MyControlNamespace.Test.ashx"/>

Suppose the above code(Test.ashx, in case of the single file model or Test.ashx.cs in case of the Code-behind model) is in your Custom Control. [The code for the handler grabs the embedded image information as IOStream and writes it to the Response object]

When the Custom control's project is built, the .ashx file will NOT be included in the resulting assembly.

So, when you ship your control's dll, it has no Test.ashx file.

So, when you request for http://localhost/AppNet/Test.ashx
or http://localhost/AppNet/MyControlNamespace.Test.ashx, the browser displays a HTTP: 404 (resource not found) error.



Solution


You have to update the web.config settings of the application to tell it to use the class, Test, as a handler for any requests to the Test.ashx file.

<httpHandlers>

<add verb="*" path="Test.ashx" type="MyControlNamespace.Test, MyControlAssembly" />

</httpHandlers>


Here, for obvious reasons, Test.ashx is not required at all (because it anyway is not shipped with your control's assembly).

[Note: In this case, you don't have to name the file, that defines the class which implements IHttpHandler, with .ashx.cs extension.

It can just be a .cs file.]

.ashx is used to avoid manipulating web.config file (because the ashx handler knows its purpose and correctly invoked the right handler). In case where you HAVE to manipulate web.config file, using .ashx extension would not be of any help.



By default the files with .aspx, .ashx extensions are compiled when first requested.

So, the Classes you define in these files cannot be accessed by other classes or files.

But if you set the Build Action Property of these files to "Compile" instead of the default "None", then these files are also compiled and the resulting .dll file (of the project) contains this compiled code.

[Note: In this case, you cannot have <%@ Page or <%@ WebHandler directives. It should be written like a regular .cs file with "using" and "namespace" elements.]