Recipe 18.2. Downloading a File from the Web Server


Problem

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

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.

Examples 18-1, 18-2 through 18-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 18-1, and the prompt that is output when the user selects a file and clicks the Download button is shown in Figure 18-2.

Figure 18-1. Listing files to be downloaded


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 commonly downloaded file types though image, audio, video, and text files are common also.

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.

Figure 18-2. File download user prompt


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 will simplify 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 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 contains data and you attempt to write a file to it, you will receive a corrupted 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 use the ContentType method to specify the content type of the file. In this example, the type is set to application/octet-stream so 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 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 from 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 create the file dynamically, it will be unnecessary 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:

 

Response.BinaryWrite([your byte array])

Response.BinaryWrite([your byte array]);

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

See Also

Recipe 20.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 18-1. Downloading a file (.aspx)

 <%@ Page Language="VB" MasterPageFile="~/ASPNetCookbookVB.master" AutoEventWireup="false" CodeFile="CH18FileDownloadVB.aspx.vb" Inherits="ASPNetCookbook.VBExamples.CH18FileDownloadVB" Title="File Download" %> <asp:Content  runat="server" ContentPlaceHolder> <div align="center" > File Download (VB) </div> <table width="90%" align="center" border="0"> <tr> <td align="center"> <asp:ListBox  Runat="server" Rows="6" /> </td> </tr> <tr> <td align="center"> <br /> <input  runat="server"  type="button"  value="Download"  onserverclick="btnDownload_ServerClick" /> </td> </tr> </table> </asp:Content> 

Example 18-2. Downloading a file code-behind (.vb)

 Option Explicit On  Option Strict On Imports System.IO Namespace ASPNetCookbook.VBExamples ''' <summary> ''' This class provides the code-behind for ''' CH18FileDownloadVB.aspx ''' </summary> Partial Class CH18FileDownloadVB Inherits System.Web.UI.Page '''*********************************************************************** ''' <summary> ''' This routine provides the event handler for the page load event. It ''' is responsible for initializing the controls on the page. ''' </summary> ''' ''' <param name="sender">Set to the sender of the event</param> ''' <param name="e">Set to the event arguments</param> Private Sub Page_Load(ByVal sender As Object, _   ByVal e As System.EventArgs) Handles Me.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 needs to verify an item was selected lstFiles.SelectedIndex = 0 End If End Sub 'Page_Load '''*********************************************************************** ''' <summary> ''' 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. ''' </summary> ''' ''' <param name="sender">Set to the sender of the event</param> ''' <param name="e">Set to the event arguments</param> Protected Sub btnDownload_ServerClick(ByVal sender As Object, _       ByVal e As System.EventArgs) 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 'CH18FileDownloadVB End Namespace 

Example 18-3. Downloading a file code-behind (.cs)

 using System; using System.IO; namespace ASPNetCookbook.CSExamples { /// <summary> /// This class provides the code-behind for /// CH18FileDownloadCS.aspx /// </summary> public partial class CH18FileDownloadCS : System.Web.UI.Page  { ///*********************************************************************** /// <summary> /// This routine provides the event handler for the page load event. /// It is responsible for initializing the controls on the page. /// </summary> /// /// <param name="sender">Set to the sender of the event</param> /// <param name="e">Set to the event arguments</param> protected void Page_Load(object sender, EventArgs e) { string[] files = null; int index; 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 needs to verify an item was selected lstFiles.SelectedIndex = 0; } } // Page_Load ///*********************************************************************** /// <summary> /// 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. /// </summary> /// /// <param name="sender">Set to the sender of the event</param> /// <param name="e">Set to the event arguments</param> protected void btnDownload_ServerClick(Object sender,               System.EventArgs e) { FileInfo file; String filename; //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 } // CH18FileDownloadCS } 



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

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