Recipe 17.2 Creating a File Download Handler

     

17.2.1 Problem

You want to create a general purpose file handler to download files of any type.

17.2.2 Solution

Create an HTTP handler to read the required file from the filesystem and send it to the browser. The steps for creating an HTTP handler are defined in Recipe 17.1.

Example 17-8 and Example 17-9 show the VB and C# class files we've written to implement a file download HTTP handler. Example 17-10 through Example 17-12 show the .aspx file and the VB and C# code-behind files for our application that demonstrates the use of the file download HTTP handler.

17.2.3 Discussion

Of the many ways you might implement a reusable file download routine that can handle virtually any file type, creating an HTTP handler makes the most sense. HTTP handlers are designed specifically to process requests for resources, and a file download request is merely a special instance of such a request.

The file download HTTP handler described in our example downloads a file from the local filesystem to the user 's system. The name of the file to download is passed in the URL used to access the HTTP handler.

The first step in implementing the file download HTTP handler is to create a class that implements IHttpHandler . The class can be part of your web project, or, if you want it to be reusable across applications, place it in a project by itself so a separate assembly can be created, as described in Recipe 17.1.

As discussed in the previous recipe, implementing the IHttpHandler interface requires the implementation of two methods : IsReusable and ProcessRequest . IsReusable is a property that explicitly returns a Boolean value that indicates whether the HTTP handler can be reused by other HTTP requests. For synchronous handlers like our example, the property should always return false so the handler is not pooled (kept in memory).

The ProcessRequest method provides all of the functionality required to download the file. The first step is to retrieve the name of the file that is to be downloaded from the URL that is being processed by the handler.

In our example, we provide only the filename in the URL that calls the handler, because all files to be downloaded are intended to be located in a single Downloads directory associated with the application. However, because a fully qualified filename is required for the download along with the size of the file, a FileInfo object is created passing the fully qualified name of the file to the constructor. The path to the Downloads directory is obtained using Server.MapPath , which translates a relative path within the web application to a fully qualified path on the web server's filesystem.

It is important to carefully review how you've implemented your file download handler to make sure it is not possible for a hacker to download files you do not intend to have downloaded. For example, if you do not restrict downloadable files to a single area, like we have done in our example, a hacker could possibly enter the following to download your web.config file:

http://aspnetcookbook/FileDownloadHandlerVB.aspx?filename=web.config

By restricting downloadable files to a single area and providing the path information in your code instead of in the URL, you can block a hacker from accessing restricted folders.


To send a file to the browser, you must write it to the Response object. Passing data in the response object is the only way to return data to the browser. Based on the content type (described later), the browser processes the data returned using the Response object.

The first step in writing the data to the Response object is to clear any data currently in the object, because no other data can be included with the file or a corrupted file error will occur.

The AddHeader method of the Response object is then used to add the name of the file being downloaded and its length.

The content type then needs to be set. In our example it is set to " application/octet-stream " so it will be treated by the browser as a binary stream and prompt the user to select the location to save the file. For your application, you may want to set the content type to the explicit file type, such as " application/PDF " or " application/msword ". Setting the content type to the explicit file type allows the browser to open it with the application defined to handle the specified file type on the client machine. For more information on content types, consult http://www.w3c.org.

The file is then written to the Response object and the response is ended to send the file to the browser.

The web.config file for our application must have an entry in the <httpHandlers> element to tell ASP.NET which URL requests need to routed to the file download HTTP handler. You use the add element and its attributes to specify each custom handler. The verb attribute of the add element defines the types of requests that are routed to the HTTP handler. The allowable values are * , GET , HEAD , and POST . The value * is a wildcard for all request types.

The path attribute defines the URL(s) that are to be processed by the HTTP handler. The path can be a single URL, as shown later, or it can be set to something like " *.download " to have the HTTP handler process all requests for URLs with a download extension. (See the note in Recipe 17.1 regarding request extensions.)

The type attribute defines the name of the assembly and class within the assembly that will process the request in the format type= " class name , assembly ". The class must be identified by its full namespace. The following code shows how to add a reference to the file download handler to the web.config file of our sample application:

 
figs/vbicon.gif
 <configuration> <system.web> <httpHandlers>  <add verb="*" path="FileDownloadHandlerVB.aspx"   type="ASPNetCookbook.VBExamples.HttpHandlers.FileDownloadHandlerVB,   VBFileDownloadHandler"/>  
figs/csharpicon.gif
 </httpHandlers> </system.web> </configuration> <configuration> <system.web> <httpHandlers>  <add verb="*" path="FileDownloadHandlerCS.aspx"   type="ASPNetCookbook.CSExamples.HttpHandlers.FileDownloadHandlerCS,   CSFileDownloadHandler"/>  </httpHandlers> </system.web> </configuration> 

To use the HTTP handler described earlier to download files, we need to set the href attribute of an HTML anchor tag to the name of the file download HTTP handler defined in the path attribute of the entry added to web.config , passing the name of the file to download in the URL. In our example, the href attribute of the anchor tag is set in the Page_Load method of the test page. A sample of the URL is shown here:

 href="FileDownloadHandlerVB.aspx?Filename=SampleDownload.txt" 

This example demonstrates downloading a file that already exists on the web server. The code can easily be altered to pass additional data in the URL, then programmatically generate the file and send it to the browser without saving it to the filesystem. This could be useful if you are dynamically creating a PDF or a CSV file requested by the user.

17.2.4 See Also

Recipe 17.1 for techniques on how to create a generic, reusable HTTP handler; http://www.w3c.org for information on content types

Example 17-8. File download HTTP handler (.vb)
 Option Explicit On Option Strict On '----------------------------------------------------------------------------- ' ' Module Name: FileDownloadHandlerVB.vb ' ' Description: This class provides a file download handler as an HTTP ' handler. ' '***************************************************************************** Imports System.IO Imports System.Web Namespace ASPNetCookbook.VBExamples.HttpHandlers Public Class FileDownloadHandlerVB Implements IHttpHandler  'The following constant is used in the URL used to access this handler to   'define the file to download   Public Const QS_FILENAME As String = "Filename"   'the following constant defines the folder containing downloadable files   Private Const DOWNLOAD_FOLDER As String = "Downloads"  '*************************************************************************** ' ' ROUTINE: IsReusable ' ' DESCRIPTION: This property defines whether another HTTP handler can ' reuse this instance of the handler. ' ' NOTE: False is always returned since this handler is synchronous ' and is not pooled. '--------------------------------------------------------------------------- Public ReadOnly Property IsReusable( ) As Boolean _ Implements IHttpHandler.IsReusable Get Return (False) End Get End Property 'IsReusable '*************************************************************************** ' ' ROUTINE: ProcessRequest ' ' DESCRIPTION: This routine provides the processing for the http request. ' It is responsible for reading the file from the local ' file system and writing it to the response object. '---------------------------------------------------------------------------  Public Sub ProcessRequest(ByVal context As HttpContext) _   Implements IHttpHandler.ProcessRequest   Dim file As FileInfo   Dim filename As String   'get the filename from the querystring   filename = context.Request.QueryString(QS_FILENAME)   'get the file data since the length is required for the download   file = New FileInfo(context.Server.MapPath(DOWNLOAD_FOLDER) & "\" & _   filename)   'write it to the browser   context.Response.Clear( )   context.Response.AddHeader("Content-Disposition", _   "attachment; filename=" & filename)   context.Response.AddHeader("Content-Length", _   file.Length.ToString( ))   context.Response.ContentType = "application/octet-stream"   context.Response.WriteFile(file.FullName)   context.Response.End( )   End Sub 'ProcessRequest  End Class 'FileDownloadHandlerVB End Namespace 

Example 17-9. File download HTTP handler (.cs)
 //---------------------------------------------------------------------------- // // Module Name: FileDownloadHandlerCS // // Description: This class provides a file download handler as an HTTP // handler. // //**************************************************************************** using System; using System.IO; using System.Web; namespace ASPNetCookbook.CSExamples.HttpHandlers { public class FileDownloadHandlerCS : IHttpHandler {  // The following constant is used in the URL used to access this handler   // to define the file to download   public const string QS_FILENAME = "Filename";     //the following constant defines the folder containing downloadable files   private const string DOWNLOAD_FOLDER = "Downloads";  //************************************************************************ // // ROUTINE: IsReusable // // DESCRIPTION: This property defines whether another HTTP handler can // reuse this instance of the handler. // // NOTE: false is always returned since this handler is synchronous // and is not pooled. //------------------------------------------------------------------------ public bool IsReusable { get { return(false); } } // IsReusable //************************************************************************ // // ROUTINE: ProcessRequest // // DESCRIPTION: This routine provides the processing for the http // request. It is responsible for reading image data from // the database and writing it to the response object. //------------------------------------------------------------------------  public void ProcessRequest(HttpContext context)   {   FileInfo file = null;   string filename = null;   // get the filename from the querystring   filename = context.Request.QueryString[QS_FILENAME];   // get the file data since the length is required for the download   file = new FileInfo(context.Server.MapPath(DOWNLOAD_FOLDER) + "\\" +   filename);   // write it to the browser   context.Response.Clear( );   context.Response.AddHeader("Content-Disposition",   "attachment; filename=" + filename);   context.Response.AddHeader("Content-Length",   file.Length.ToString( ));   context.Response.ContentType = "application/octet-stream";   context.Response.WriteFile(file.FullName);   context.Response.End( );   } // ProcessRequest  } // FileDownloadHandlerCS } 

Example 17-10. Using the file download HTTP handler (.aspx)
 <%@ Page Language="vb" AutoEventWireup="false" Codebehind="CH17TestHTTPFileDownloadHandlerVB.aspx.vb" Inherits="ASPNetCookbook.VBExamples.CH17TestHTTPFileDownloadHandlerVB" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title>Test HTTP File Download Handler</title> <link rel="stylesheet" href="css/ASPNetCookbook.css"> </head> <body leftmargin="0" marginheight="0" marginwidth="0" topmargin="0"> <form id="frmTestFileDownloadHandler" method="post" runat ="server"> <table width="100%" cellpadding ="0" cellspacing="0" border="0"> <tr> <td align="center"> <img src="images/ASPNETCookbookHeading_blue.gif"> </td> </tr> <tr> <td class="dividerLine"> <img src="images/spacer.gif" height="6" border="0"></td> </tr> </table> <table width="90%" align="center" border="0"> <tr> <td align="center">&nbsp;</td> </tr> <tr> <td align="center" class="PageHeading"> HTTP Handler For File Downloads (VB) </td> </tr> <tr> <td><img src="images/spacer.gif" height="10" border="0"></td> </tr> <tr> <td align="center" class="SubHeading"> Click the link below to download the sample file using an HTTP Handler<br /> <br />  <a id="anDownload" runat="server" ></a>  </td> </tr> </table> </form> </body> </html> 

Example 17-11. Using the file download HTTP handler code-behind (.vb)
 Option Explicit On Option Strict On '----------------------------------------------------------------------------- ' ' Module Name: CH17TestHTTPFileDownloadHandlerVB.aspx.vb ' ' Description: This module CH17TestHTTPFileDownloadHandlerVB the code-behind ' for the CH17TestHTTPFileDownloadHandlerVB.aspx page. ' '***************************************************************************** Imports ASPNetCookbook.VBExamples.HttpHandlers Namespace ASPNetCookbook.VBExamples Public Class CH17TestHTTPFileDownloadHandlerVB Inherits System.Web.UI.Page 'controls on the form Protected anDownload As System.Web.UI.HtmlControls.HtmlAnchor '*************************************************************************** ' ' ROUTINE: Page_Load ' ' DESCRIPTION: This routine provides the event handler for the page load ' event. It is responsible for initializing the controls ' on the page. '--------------------------------------------------------------------------- Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load  Const FILE_TO_DOWNLOAD As String = "SampleDownload.txt"   'set the text and href of the download anchor   anDownload.InnerText = FILE_TO_DOWNLOAD   anDownload.HRef = "FileDownloadHandlerVB.aspx?" & _   FileDownloadHandlerVB.QS_FILENAME & "=" & _   FILE_TO_DOWNLOAD  End Sub 'Page_Load End Class 'HTTPFileDownloadHandlerDemo_VB End Namespace 

Example 17-12. Using the file download HTTP handler code-behind (.cs)
 //---------------------------------------------------------------------------- // // Module Name: CH17TestHTTPFileDownloadHandlerCS.aspx.cs // // Description: This module provides the code behind for the // CH17TestHTTPFileDownloadHandlerCS.aspx page // //**************************************************************************** using ASPNetCookbook.CSExamples.HttpHandlers; using System; namespace ASPNetCookbook.CSExamples { public class CH17TestHTTPFileDownloadHandlerCS : System.Web.UI.Page { // controls on the form protected System.Web.UI.HtmlControls.HtmlAnchor anDownload; //************************************************************************ // // ROUTINE: Page_Load // // DESCRIPTION: This routine provides the event handler for the page // load event. It is responsible for initializing the // controls on the page. //------------------------------------------------------------------------ private void Page_Load(object sender, System.EventArgs e) {  const string FILE_TO_DOWNLOAD = "SampleDownload.txt";   // set the text and href of the download anchor   anDownload.InnerText = FILE_TO_DOWNLOAD;   anDownload.HRef = "FileDownloadHandlerCS.aspx?" +   FileDownloadHandlerCS.QS_FILENAME + "=" +   FILE_TO_DOWNLOAD;  } // Page_Load } // CH17TestHTTPFileDownloadHandlerCS } 



ASP. NET Cookbook
ASP.Net 2.0 Cookbook (Cookbooks (OReilly))
ISBN: 0596100647
EAN: 2147483647
Year: 2006
Pages: 179

Similar book on Amazon

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