Recipe 15.1 Downloading a File from the Web Server

     

15.1.1 Problem

You need to provide the ability for a user to download a file from the web server.

15.1.2 Solution

Use the Directory and FileInfo classes to gather and present the names of the files you want to make available for download to the user. Display their names in a listbox with a button to initiate the download. When the user clicks the button, stream the selected file to the browser.

In the .aspx file, add a listbox and a Download (or equivalently named) button.

In the code-behind class for the page, use the .NET language of your choice to:

  1. Create a list of available files to download using the GetFiles method of the Directory class.

  2. Populate the ListBox with the filenames by binding the list of files to the ListBox .

  3. Process the Download button click event and stream the selected file to the browser using the Response object.

Example 15-1 through Example 15-3 show the .aspx file and VB and C# code-behind files for an application that illustrates our solution by populating the listbox with a list of files located in the application's images directory. The populated listbox is shown in Figure 15-1, and the prompt that is output when the user selects a file and clicks Download is shown in Figure 15-2.

Figure 15-1. Listing files to be downloaded
figs/ancb_1501.gif

Figure 15-2. File download user prompt
figs/ancb_1502.gif

15.1.3 Discussion

Downloading a file to the browser for display, storage, or printing is a common requirement of a web application. PDF and Word files are perhaps the most ubiquitous download files types, although image, audio, video, and text files are quite common as well.

Downloading a file from a server is a two-step process. The first step is to gather and present to the user a list of the available files that can be downloaded along with a button to initiate the download. The second step is to process the button click event and stream the selected file to the browser.

In our example, we use a listbox to present a list of available files to the user. The list is populated in the Page_Load method of the code-behind with a list of files located in the images directory of the application. (In a production application, you may want to create a download folder instead.)

To populate the listbox, we use the GetFiles method of the Directory class to gather the fully qualified filenames of the files in the specified folder and return them as an array. The GetFiles method returns a fully qualified filename for each file it finds, so our code needs to remove the path information for each file to simplify the list we present to the user.

Next, we bind the files array to the listbox and select the first entry in the list.

Selecting the first entry in the list simplifies the code because no validation is required if we can always assume an item is selected.


When the user clicks the Download button to initiate the download, the btnDownload_ServerClick method in the code-behind executes. In this routine, we use the MapPath method of the Server class to create a fully qualified filename, which we use to instantiate a FileInfo object to provide easy access to the length of the file that is needed for the download.

To stream a file to a browser, you must write it to the Response object. The first step in writing a file to the Response object is to call its Clear method to remove any data currently in the buffer stream. If the Response object already contains data, when you attempt to write a file to it, you will receive a corrupt file error.

Before writing the file, use the AddHeader method of the Response object to add the name of the file being downloaded and its length to the output stream. You must also use the ContentType method to specify the content type of the file. In this example, the type is set to application/octet-stream so that the browser will treat the output stream as a binary stream and prompt the user to select a location to which to save the file. In your own application you may want to set the content type to an 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.

Now, at last, you are ready to write the file to the Response object using Response.WriteFile . When the operation is complete, call Response.End to send the file to the browser.

Things to remember when downloading files:


  • Any code that appears after the Response.End statement will not be executed. The Response.End statement sends all buffered data in the Response object to the client, stops the execution of the page, and raises the Application_EndRequest event. For more information on the application behavior when calling Response.End , refer to Knowledge Base article KB312629.

  • The only data that can be included in the Response stream is the file to download. If any other data is included, the downloaded file will be corrupted. This may occur if your application uses the Application_EndRequest method to append a footer to all pages.

In our example, a list of files currently residing on the filesystem is presented to the user to select from and download. If your application is going to dynamically create the file, it is not necessary to present a list or to save the file to the filesystem. Instead, remove the listbox and add whatever controls are needed to collect the information you need to dynamically create the file. When the user clicks Download, create your file and generate a byte array containing the file data. Instead of using the WriteFile method of the Response object, use the BinaryWrite method, as shown here:

 
figs/vbicon.gif
 Response.BinaryWrite(   [your byte array]   ) 
figs/csharpicon.gif
 Response.BinaryWrite(   [your byte array]   ); 

For another approach to implementing the solution described in this example using an HTTP handler, refer to Recipe 17.2.

15.1.4 See Also

Recipe 17.2 for implementing file downloads with an HTTP handler; Knowledge Base article KB312629 for more information on the system operation when Response.End , Response.Redirect , and Server.Transfer are called

Example 15-1. Downloading a file (.aspx)
 <%@ Page Language="vb" AutoEventWireup="false" Codebehind="CH15FileDownloadVB.aspx.vb" Inherits="ASPNetCookbook.VBExamples.CH15FileDownloadVB" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title>File Download</title> <link rel="stylesheet" href="css/ASPNetCookbook.css"> </head> <body leftmargin="0" marginheight="0" marginwidth="0" topmargin="0"> <form id="frmDownload" 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"> File Download (VB) </td> </tr> <tr> <td><img src="images/spacer.gif" height="10" border="0"></td> </tr> <tr> <td align="center">  <asp:ListBox ID="lstFiles" Runat="server" Rows="6" />  </td> </tr> <tr> <td align="center"> <br />  <input id="btnDownload" runat="server"   type="button" value="Download">  </td> </tr> </table> </form> </body> </html> 

Example 15-2. Downloading a file code-behind (.vb)
 Option Explicit On Option Strict On '----------------------------------------------------------------------------- ' ' Module Name: CH15FileDownloadVB.aspx.vb ' ' Description: This module provides the code behind for the ' CH15FileDownloadVB.aspx page ' '***************************************************************************** Imports System Imports System.IO Imports System.Web.UI Namespace ASPNetCookbook.VBExamples Public Class CH15FileDownloadVB Inherits System.Web.UI.Page 'controls on the form Protected lstFiles As System.Web.UI.WebControls.ListBox Protected WithEvents btnDownload As HtmlControls.HtmlInputButton '************************************************************************* ' ' 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 Dim files( ) As String Dim index As Integer If (Not Page.IsPostBack) Then  'get list of files in the images directory (just for example here)   files = Directory.GetFiles(Server.MapPath("images"))   'for display purposes, remove the path to the file   For index = 0 To files.Length - 1   files(index) = New FileInfo(files(index)).Name   Next index   'bind the list of files to the listbox on the form   lstFiles.DataSource = files   lstFiles.DataBind( )   'select the first entry in the list   'NOTE: This is done to simplify the example since preselecting an   ' item eliminates the need to verify an item was selected   lstFiles.SelectedIndex = 0  End If End Sub 'Page_Load '*************************************************************************** ' ' ROUTINE: btnDownload_ServerClick ' ' DESCRIPTION: This routine provides the event handler for the download ' button click event. It is responsible for reading the ' selected file from the file system and streaming it to ' the browser. '---------------------------------------------------------------------------  Private Sub btnDownload_ServerClick(ByVal sender As Object, _   ByVal e As System.EventArgs) _   Handles btnDownload.ServerClick   Dim file As FileInfo   Dim filename As String   'get the fully qualified name of the selected file   filename = Server.MapPath("images") & "\" & _   lstFiles.SelectedItem.Text   'get the file data since the length is required for the download   file = New FileInfo(filename)   'write it to the browser   Response.Clear( )   Response.AddHeader("Content-Disposition", _   "attachment; filename=" & lstFiles.SelectedItem.Text)   Response.AddHeader("Content-Length", _   file.Length.ToString( ))   Response.ContentType = "application/octet-stream"   Response.WriteFile(filename)   Response.End( )   End Sub 'btnDownload_ServerClick  End Class 'CH15FileDownloadVB End Namespace 

Example 15-3. Downloading a file code-behind (.cs)
 //---------------------------------------------------------------------------- // // Module Name: CH15FileDownloadCS.aspx.cs // // Description: This module provides the code behind for the // CH15FileDownloadCS.aspx page // //**************************************************************************** using System; using System.IO; namespace ASPNetCookbook.CSExamples { public class CH15FileDownloadCS : System.Web.UI.Page { // controls on the form protected System.Web.UI.WebControls.ListBox lstFiles; protected System.Web.UI.HtmlControls.HtmlInputButton btnDownload; //************************************************************************ // // 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) { string[] files = null; int index; // wire the download button event handler this.btnDownload.ServerClick += new EventHandler(this.btnDownload_ServerClick); if (!Page.IsPostBack) {  // get list of files in the images directory   files = Directory.GetFiles(Server.MapPath("images"));   // for display purposes, remove the path to the file   for (index = 0; index < files.Length; index++)   {   files[index] = new FileInfo(files[index]).Name;   }   // bind the list of files to the listbox on the form   lstFiles.DataSource = files;   lstFiles.DataBind( );   // select the first entry in the list   // NOTE: This is done to simplify the example since preselecting an   // item eliminates the need to verify an item was selected   lstFiles.SelectedIndex = 0;  } } // Page_Load //************************************************************************ // // ROUTINE: btnDownload_ServerClick // // DESCRIPTION: This routine provides the event handler for the download // button click event. It is responsible for reading the // selected file from the file system and streaming it to // the browser. //------------------------------------------------------------------------  private void btnDownload_ServerClick(object sender,   System.EventArgs e)   {   FileInfo file = null;   string filename = null;   // get the fully qualified name of the selected file   filename = Server.MapPath("images") + "\\" +   lstFiles.SelectedItem.Text;   // get the file data since the length is required for the download   file = new FileInfo(filename);   // write it to the browser   Response.Clear( );   Response.AddHeader("Content-Disposition",   "attachment; filename=" + lstFiles.SelectedItem.Text);   Response.AddHeader("Content-Length",   file.Length.ToString( ));   Response.ContentType = "application/octet-stream";   Response.WriteFile(filename);   Response.End( );   } // btnDownload_ServerClick  } // CH15FileDownloadCS } 



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

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