Creating HTTP Handlers


An HTTP Handler is a .NET class that executes whenever you make a request for a file at a certain path. Each type of resource that you can request from an ASP.NET application has a corresponding handler.

For example, when you request an ASP.NET page, the Page class executes. The Page class is actually an HTTP Handler because it implements the IHttpHandler interface.

Other examples of HTTP Handlers are the TRaceHandler class, which displays application-level trace information when you request the trace.axd page, and the ForbiddenHandler class, which displays an Access Forbidden message when you attempt to request source code files from the browser.

You can implement your own HTTP handlers. For example, imagine that you want to store all your images in a database table. However, you want use normal HTML <img> tags to display images in your web pages. In that case, you can map any file that has a .gif or .jpeg extension to a custom image HTTP handler. The image HTTP handler can retrieve images from a database automatically whenever an image request is made.

Or, imagine that you want to expose an RSS feed from your website. In that case, you can create a RSS HTTP Handler that displays a list of blog entries or articles hosted on your website.

You can create an HTTP Handler in two ways. You can either create something called a Generic Handler or you can implement the IHttpHandler interface in a custom class. This section explores both methods of creating an HTTP Handler.

Creating a Generic Handler

The easiest way to create a new HTTP Handler is to create a Generic Handler. When you create a Generic Handler, you create a file that ends with the extension .ashx. Whenever you request the .ashx file, the Generic Handler executes.

You can think of a Generic Handler as a very lightweight ASP.NET page. A Generic Handler is like an ASP.NET page that contains a single method that renders content to the browser. You can't add any controls declaratively to a Generic Handler. A Generic Handler also doesn't support events such as the Page Load or Page PreRender events.

In this section, we create a Generic Handler that dynamically generates an image from a string of text. For example, if you pass the string Hello World! to the handler, the handler returns an image of the text Hello World!.

The Generic Handler is contained in Listing 25.14.

Listing 25.14. ImageTextHandler.ashx

<%@ WebHandler Language="VB"  %> Imports System Imports System.Web Imports System.Drawing Imports System.Drawing.Imaging   Public Class ImageTextHandler      Implements IHttpHandler       Public Sub ProcessRequest(ByVal context As HttpContext) _     Implements IHttpHandler.ProcessRequest         ' Get parameters from querystring         Dim text As String = context.Request.QueryString("text")         Dim font As String = context.Request.QueryString("font")         Dim size As String = context.Request.QueryString("size")           ' Create Font         Dim fntText As New Font(font, Single.Parse(size))           ' Calculate image width and height         Dim bmp As New Bitmap(10, 10)         Dim g As Graphics = Graphics.FromImage(bmp)         Dim bmpSize As SizeF = g.MeasureString(text, fntText)         Dim width As Integer = CType(Math.Ceiling(bmpSize.Width), Integer)         Dim height As Integer = CType(Math.Ceiling(bmpSize.Height), Integer)         bmp = New Bitmap(bmp, width, height)         g.Dispose()           ' Draw the text         g = Graphics.FromImage(bmp)         g.Clear(Color.White)         g.DrawString(text, fntText, Brushes.Black, New PointF(0, 0))         g.Dispose()           ' Save bitmap to output stream         bmp.Save(context.Response.OutputStream, ImageFormat.Gif)     End Sub       Public ReadOnly Property IsReusable() As Boolean _     Implements IHttpHandler.IsReusable         Get             Return True         End Get     End Property   End Class 

The ImageTextHandler in Listing 25.14 includes one method and one property. The ProcessRequest() method is responsible for outputting any content that the handler renders to the browser.

In Listing 25.14, the image text, font, and size are retrieved from query string fields. You specify the image that you want to return from the handler by making a request that looks like this:

/ImageTextHandler.ashx?text=Hello&font=Arial&size=30


Next, a bitmap is created with the help of the classes from the System.Drawing namespace. The bitmap is actually created twice. The first one is used to measure the size of the bitmap required for generating an image that contains the text. Next, a new bitmap of the correct size is created, and the text is drawn on the bitmap.

After the bitmap has been created, it is saved to the HttpResponse object's OutputStream so that it can be rendered to the browser.

The handler in Listing 25.14 also includes an IsReusable property. The IsReusable property indicates whether the same handler can be reused over multiple requests. You can improve your application's performance by returning the value true. Because the handler isn't maintaining any state information, there is nothing wrong with releasing it back into the pool so that it can be used with a future request.

The page in Listing 25.15 illustrates how you can use the ImageTextHandler.ashx file. This page contains three HTML <img> tags that pass different query strings to the handler (see Figure 25.4).

Figure 25.4. Displaying text images with an HTTP Handler.


Listing 25.15. ShowImageTextHandler.aspx

<%@ Page Language="VB" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head  runat="server">     <title>Show ImageTextHandler</title> </head> <body>     <form  runat="server">     <div>          <img src="/books/3/444/1/html/2/ImageTextHandler.ashx?text=Some Text&font=WebDings&size=42" />     <br />     <img src="/books/3/444/1/html/2/ImageTextHandler.ashx?text=Some Text&font=Comic Sans MS&size=42" />     <br />     <img src="/books/3/444/1/html/2/ImageTextHandler.ashx?text=Some Text&font=Courier New&size=42" />          </div>     </form> </body> </html> 

Implementing the IHttpHandler Interface

The big disadvantage of a Generic Handler is that you cannot map a Generic Handler to a particular page path. For example, you cannot execute a Generic Handler whenever someone requests a file with the extension .gif.

If you need more control over when an HTTP Handler executes, then you can create a class that implements the IHttpHandler interface.

For example, the class in Listing 25.16 represents an Image HTTP Handler. This handler retrieves an image from a database table and renders the image to the browser.

Listing 25.16. App_Code\ImageHandler.vb

[View full width]

Imports System Imports System.Web Imports System.Data Imports System.Data.SqlClient Imports System.Web.Configuration Namespace AspNetUnleashed     Public Class ImageHandler         Implements IHttpHandler         Const connectionStringName As String = "Images"         Public Sub ProcessRequest(ByVal context As HttpContext) _         Implements IHttpHandler.ProcessRequest             ' Don't buffer response             context.Response.Buffer = False             ' Get file name             Dim fileName As String = VirtualPathUtility.GetFileName(context.Request.Path)             ' Get image from database             Dim conString As String = WebConfigurationManager.ConnectionStrings (connectionStringName).ConnectionString             Dim con As New SqlConnection(conString)             Dim cmd As New SqlCommand("SELECT Image FROM Images WHERE FileName=@FileName",  con)             cmd.Parameters.AddWithValue("@fileName", fileName)             Using con                 con.Open()                 Dim reader As SqlDataReader = cmd.ExecuteReader(CommandBehavior .SequentialAccess)                 If reader.Read() Then                     Dim bufferSize As Integer = 8040                     Dim chunk(bufferSize) As Byte                     Dim retCount As Long                     Dim startIndex As Long = 0                     retCount = reader.GetBytes(0, startIndex, chunk, 0, bufferSize)                     While retCount = bufferSize                         context.Response.BinaryWrite(chunk)                         startIndex += bufferSize                         retCount = reader.GetBytes(0, startIndex, chunk, 0, bufferSize)                     End While                     Dim actualChunk() As Byte = New Byte(retCount - 1) {}                     Buffer.BlockCopy(chunk, 0, actualChunk, 0, CType(retCount - 1, Integer))                     context.Response.BinaryWrite(actualChunk)                 End If             End Using         End Sub         Public ReadOnly Property IsReusable() As Boolean _         Implements IHttpHandler.IsReusable             Get                 Return True             End Get         End Property     End Class End Namespace 

After you create a class that implements the IHttpHandler interface, you need to register the class in the web configuration file. The web configuration file in Listing 25.17 includes an httpHandlers section that associates the .gif, .jpeg, and .jpg extensions with the Image handler.

Listing 25.17. Web.Config

<?xml version="1.0"?> <configuration>   <connectionStrings>     <add name="Images"        connectionString="Data Source=.\SQLExpress;Integrated            Security=True;AttachDBFileName=|DataDirectory|ImagesDB.mdf;            User Instance=True"/>   </connectionStrings>     <system.web>       <httpHandlers>         <add path="*.gif" verb="*"             type="AspNetUnleashed.ImageHandler" validate="false" />         <add path="*.jpeg" verb="*"             type="AspNetUnleashed.ImageHandler" validate="false" />         <add path="*.jpg" verb="*"             type="AspNetUnleashed.ImageHandler" validate="false" />       </httpHandlers>            </system.web> </configuration> 

When you register a handler, you specify the following four attributes:

  • pathEnables you to specify the path associated with the handler. You can use wildcards in the path expression.

  • verbEnables you to specify the HTTP verbs, such as GET or POST, associated with the handler. You can specify multiple verbs in a comma-separated list. You can represent any verb with the * wildcard.

  • typeEnables you to specify the name of the class that implements the handler.

  • validateEnables you to specify whether the handler is loaded during application startup. When true, the handler is loaded at startup. When false, the handler is not loaded until a request associated with the handler is made. This second option can improve your application's performance when a handler is never used.

The page in Listing 25.18 uses the ImageHandler to render its images. The page enables you to upload new images to a database named ImagesDB. The page also displays existing images (see Figure 25.5).

Figure 25.5. Displaying images with the ImageHandler.


Listing 25.18. ImageUpload.aspx

<%@ Page Language="VB" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <script runat="server">     Sub btnAdd_Click(ByVal sender As Object, ByVal e As EventArgs)         If upFile.HasFile Then             srcImages.Insert()         End If     End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head  runat="server">     <style type="text/css">         .fileList li         {             margin-bottom:5px;         }     </style>     <title>Image Upload</title> </head> <body>     <form  runat="server">     <div>     <asp:Label                  Text="Image File:"         AssociatedControl         Runat="server" />     <asp:FileUpload                  Runat="server" />     <asp:Button                  Text="Add Image"         OnClick="btnAdd_Click"          Runat="server" />     <hr />     <asp:GridView                  DataSource         AutoGenerateColumns="false"         ShowHeader="false"         GridLines="None"         Runat="server">         <Columns>         <asp:ImageField              DataImageUrlField="FileName"              DataAlternateTextField="FileName" />         </Columns>     </asp:GridView>     <asp:SqlDataSource                  ConnectionString="<%$ ConnectionStrings:Images %>"         SelectCommand="SELECT FileName FROM Images"         InsertCommand="INSERT Images (FileName,Image)            VALUES (@FileName,@FileBytes)"         Runat="server">         <InsertParameters>             <asp:ControlParameter Name="FileName" Control                PropertyName="FileName" />             <asp:ControlParameter Name="FileBytes" Control                PropertyName="FileBytes" />         </InsertParameters>     </asp:SqlDataSource>                  </div>     </form> </body> </html>

Registering Extensions with Internet Information Server

The web server included with Visual Web Developer maps all requests to the ASP.NET Framework. For example, if you create an HTTP Handler that handles requests for .gif files, then you don't have to do anything special when using the handler with the Visual Web Developer web server.

Internet Information Server, on the other hand, does not map all requests to the ASP.NET Framework. In particular, it does not map requests for .gif files to ASP.NET. If you want to use a special extension for a handler, then you must configure Internet Information Server to map that extension to the ASP.NET Framework.

If you are serving your pages with Internet Information Server 6.0 (included with Windows Server 2003), then you can create something called a wildcard application mapping. A wildcard application mapping enables you to map all page requests to an application such as the ASP.NET Framework. Follow these steps to configure a wildcard mapping for ASP.NET:

1.

Open Internet Information Services by selecting Start, Control Panel, Administrative Tools, Internet Information Services.

2.

Open the property sheet for a particular website or virtual directory.

3.

Open the Application Configuration dialog box by selecting the Directory tab and clicking the Configuration button.

4.

Select the Mappings tab.

5.

Click the Insert button at the bottom of the Mappings tab to open the Add/Edit Application Extension Mapping dialog box (see Figure 25.6).

Figure 25.6. Adding a wildcard application mapping.


6.

In the Executable field, enter the path to the ASP.NET ISAPI DLL. (You can copy and paste this path from the Application Mapping for the .aspx extension.)

After you complete these steps, all requests made for any type of file are handled by the ASP.NET Framework. If you make a request for a .gif image, then any handlers that you have registered in the web configuration file for the .gif extension will execute.

Earlier versions of Internet Information Server, such as the version included with Microsoft Windows XP, do not support wildcard application mappings. You must map each file extension that you want to associate with the ASP.NET Framework one by one. Follow these steps to map the .gif extension to the ASP.NET Framework:

1.

Open Internet Information Services by selecting Start, Control Panel, Administrative Tools, Internet Information Services.

2.

Open the property sheet for a particular website or virtual directory.

3.

Open the Application Configuration dialog box by selecting the Directory tab and clicking the Configuration button.

4.

Select the Mappings tab (see Figure 25.7).

Figure 25.7. Adding an application mapping.


5.

Click the Add button to open the Add/Edit Application Extension Mapping dialog box.

6.

In the Executable field, enter the path to the ASP.NET ISAPI DLL. (You can copy and paste this path from the Application Mapping for the .aspx extension.)

7.

In the Extension field, enter .gif.

After you complete these steps, requests for .gif images are handled by the ASP.NET Framework. If you have registered an HTTP handler for the .gif extension in the web configuration file, then the HTTP Handler will execute whenever someone makes a request for a .gif file.

Creating an Asynchronous HTTP Handler

When you create an HTTP Handler by creating either a Generic Handler or implementing the IHttpHandler interface, you are creating a synchronous handler. In this section, you learn how to create an asynchronous handler.

The advantage of creating an asynchronous handler is scalability. The ASP.NET Framework maintains a limited pool of threads that are used to service requests. When the ASP.NET Framework receives a request for a file, it assigns a thread to handle the request. If the ASP.NET Framework runs out of threads, the request is queued until a thread becomes available. If too many threads are queued, then the framework rejects the page request with a 503Server Too Busy response code.

If you execute an HTTP Handler asynchronously, then the current thread is released back into the thread pool so that it can be used to service another page request. While the asynchronous handler is executing, the ASP.NET framework can devote its attention to handling other requests. When the asynchronous handler completes its work, the framework reassigns a thread to the original request and the handler can render content to the browser.

Note

You can configure the ASP.NET thread pool with the httpRuntime element in the web configuration file. You can modify the appRequestQueueLimit, minFreeThreads, and minLocalRequestFreeThreads attributes to control how many requests the ASP.NET Framework queues before giving up and sending an error.


You create an asynchronous HTTP handler by implementing the IHttpAsyncHandler interface. This interface derives from the IHttpHandler interface and adds two additional methods:

  • BeginProcessRequestCalled to start the asynchronous task.

  • EndProcessRequestCalled when the asynchronous task completes.

For example, the file in Listing 25.19 contains an asynchronous handler that grabs an RSS feed from the Microsoft MSDN website.

Listing 25.19. App_Code\RSSHandler.vb

[View full width]

Imports System Imports System.Web Imports System.Net Imports System.IO Namespace AspNetUnleashed     Public Class RSSHandler         Implements IHttpAsyncHandler         Private _context As HttpContext         Private _request As WebRequest         Public Function BeginProcessRequest(ByVal context As HttpContext, ByVal cb As  AsyncCallback, ByVal extraData As Object) As IAsyncResult Implements IHttpAsyncHandler .BeginProcessRequest             ' Store context             _context = context             ' Initiate call to RSS feed             _request = WebRequest.Create("http://msdn.microsoft.com/asp.net/rss.xml")             Return _request.BeginGetResponse(cb, extraData)         End Function         Public Sub EndProcessRequest(ByVal result As IAsyncResult) Implements  IHttpAsyncHandler.EndProcessRequest             ' Get the RSS feed             Dim rss As String = String.Empty             Dim response As WebResponse = _request.EndGetResponse(result)             Using response                 Dim reader As New StreamReader(response.GetResponseStream())                 rss = reader.ReadToEnd()             End Using             _context.Response.Write(rss)         End Sub         Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable             Get                 Throw New Exception("The IsReusable property is not implemented.")             End Get         End Property         Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler .ProcessRequest             Throw New Exception("The ProcessRequest method is not implemented.")         End Sub     End Class End Namespace 

The handler in Listing 25.19 implements both the BeginProcessRequest() and EndProcessRequest() methods required by the IHttpAsyncHandler interface.

The BeginProcessRequest() method uses the WebRequest class to request the page that contains the RSS headlines from the MSDN website. The WebRequest.BeginGetResponse() method is used to retrieve the remote page asynchronously.

When the BeginGetResponse() method completes, the handler's EndProcessRequest() method is called. This method retrieves the page and renders the contents of the page to the browser.

Before you can use the RSSHandler, you need to register it in your web configuration file. The web configuration file in Listing 25.20 includes an <httpHandlers> section that registers the RSSHandler and associates the handler with the .rss extension.

Listing 25.20. Web.Config

<?xml version="1.0"?> <configuration>     <system.web>       <httpHandlers>         <add path="*.rss" verb="*" type="AspNetUnleashed.RSSHandler"/>       </httpHandlers>            </system.web> </configuration> 

After you register the RSSHandler, you can execute the handler by making a request for any file that ends with the extension .rss. If you have a news reader, such as SharpReader, then you can enter a path like the following in the reader's address bar:

http://localhost:2026/YourApp/news.rss 


The page in Listing 25.21 contains a GridView and XmlDataSource control. The XmlDataSource control calls the RssHandler to retrieve the headlines that are displayed in the GridView control (see Figure 25.8).

Figure 25.8. Retrieving an RSS feed asynchronously.


Listing 25.21. ShowRSSHandler.aspx

<%@ Page Language="VB" %> <%@ Import Namespace="System.IO" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <script runat="server">     Sub Page_Load()         Dim pagePath As String = Request.Url.OriginalString         Dim rssPath As String = Path.ChangeExtension(pagePath, ".rss")         srcRSS.DataFile = rssPath     End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head  runat="server">     <title>Show RSS Handler</title> </head> <body>     <form  runat="server">     <div>          <asp:GridView                  DataSource         AutoGenerateColumns="false"         Runat="server">         <Columns>         <asp:TemplateField HeaderText="Articles">         <ItemTemplate>             <asp:HyperLink                                  Text='<%# XPath("title") %>'                 NavigateUrl='<%# XPath("link") %>'                 Runat="server" />         </ItemTemplate>         </asp:TemplateField>         </Columns>     </asp:GridView>              <asp:XmlDataSource                  XPath="//item"         Runat="server" />          </div>     </form> </body> </html> 




ASP. NET 2.0 Unleashed
ASP.NET 2.0 Unleashed
ISBN: 0672328232
EAN: 2147483647
Year: 2006
Pages: 276

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net