How to download a file from the Web server in ASP.NET in C#

You should use the Directory FileInfo classes to collect and present the names of the files you want to make available for download to the end user.  You can 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.  The next picture presents this functionality.

 

Downloading a file from the Web site in C#

Downloading a file from the Web site in C#

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

1. Collect information about available files to download, by using the GetFiles method of the Directory class.

2. Fill in the ListBox with the filenames by biding 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.

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:

1. Your code has to collect and present to the user a list of the available files that can be downloaded along with a button to initiate the download.

2. You code has to process the button click event and stream the selected file to the browser.

In the a ListBox is used 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 C:\Downloads directory. You can use dedicated directory on the Web server instead.

The ListBox is populated by using GetFiles method of the Directory class to collect 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 your code needs to remove the path information for each file to simplify the list you present to the user.

Next, you should bind the files array to the ListBox and select the first entry in the list.

When the user clicks the Download button to initiate the download, the btnDownload_Click method in the code-behind executes. This routine calls another routine BufferedFileDownload.

The routine BufferedFileDownload does the main tasks. It checks if the file exists. To stream a file to a browser it 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, you should 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 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.

Your file will be read block after block of bytes specified by the variable bufsz. By default bufsz = 4096, but if your file is smaller you use its length as bufsz. When you read one block you are ready to write it to the file to the Response object using Response.BinaryWrite. Finally you read and write the rest of bytes. When the operation is complete you check if bytes transferred are equal to the length of the file.

The next lines show markup in .aspx file in our case TestDownloadVC.aspx

<%@ Page Language=”C#” AutoEventWireup=”true” CodeBehind=”TestDownloadVC.aspx.cs” Inherits=”FileDownloadVC.TestDownloadVC” %>

 

<!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></title>

</head>

<body style=”height: 22px”>

<form id=”form1″ runat=”server”>

<div align=”center”>

<asp:Label ID=”lblTitle” runat=”server” Font-Bold=”True”  Text=”Select file and press Download”></asp:Label>

<br />

<asp:ListBox ID=”FilesList” runat=”server” Height=”162px” Width=”226px”> </asp:ListBox>

<br />

<asp:Button ID=”btnDownload” runat=”server” onclick=”btnDownload_Click” Text=”Download” />

</div>

</form>

</body>

</html>

 

The next lines present code-behind in C#

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.IO;

 

namespace FileDownloadVC

{

public partial class TestDownloadVC : System.Web.UI.Page

{

//

// The next routine provides the event handler for the page load event.

// It is responsible for initializing the controls on the page.

//

protected void Page_Load(object sender, EventArgs e)

{

string[] files = null;

int idx;

// Set up the download button event handler

this.btnDownload.Click += new EventHandler(this.btnDownload_Click);

if (!Page.IsPostBack)

{

// Get the list of files in the specified directory

// Note: If you want to use specific directory from the Web server replace the next row with

//           files = Directory.GetFiles(Server.MapPath(“NameOfDirectory”));

//           where the NameOfDirectory is the place where you keep files for downloading

//

files = Directory.GetFiles(“C:\\Downloads\\”);

// Remove the path to the files

for (idx = 0; idx < files.Length; idx++)

{

files[idx] = new FileInfo(files[idx]).Name;

}

// Bind the list of files to the listbox on the form

FilesList.DataSource = files;

FilesList.DataBind();

// Select the first entry in the list

FilesList.SelectedIndex = 0;

}

}

//

// The next 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.

//

protected void btnDownload_Click(object sender, EventArgs e)

{

if (!BufferedFileDownload())

{

System.Web.UI.ScriptManager.RegisterStartupScript(this, GetType(), “FileNotDownloadedWarning”, “alert(‘File was not downloaded!’)”, true);

}

}

//

// The next routine processes file selected for download.

// It returs true if the chosen file is processed without errors.

// Internally it does the following steps:

// 1. Checks if file exists

// 2. Specifies the size of buffer.

// 3. Calculates the number of blocks of bytes which will be buffered and rest of bytes if they exist

// 4. Does buffered transfer

//

protected bool BufferedFileDownload()

{

FileInfo file = null;

string filename = null;

FileStream fromFile = null;

BinaryReader binReader = null;

 

// Get the fully qualified name of the selected file

// Note: If you have used specific directory from the Web server you have to replace

//           the next row with

//           filename = Directory.GetFiles(Server.MapPath(“NameOfDirectory”)) + “\\” + FilesList.SelectedItem.Text;

//           where the NameOfDirectory is the place where you keep files for downloading

 

filename = “C:\\Downloads\\” + FilesList.SelectedItem.Text;

 

// Get the file data

file = new FileInfo(filename);

 

if (!file.Exists)

{

System.Web.UI.ScriptManager.RegisterStartupScript(this, GetType(),

“FileNotFoundWarning”, “alert(‘File is not available now!’)”, true);

return false;

}

 

try

{

// Clear the content of the responce

Response.Clear();

Response.AddHeader(“Content-Disposition”, “attachment; filename=” + FilesList.SelectedItem.Text);

Response.AddHeader(“Content-Length”, file.Length.ToString());

// Set the content type

Response.ContentType = “application/octet-stream”;

 

// Buffered download in blocks of 4096 bytes

 

int bufsz = 0;      // size of buffer

long block = 1;     // block of bytes

long blocks = 0;    // number of blocks of bytes

int rest = 0;       // number of bytes after the final block of bytes

// possible values are from 0 to size of buffer-1

 

// In the next if…else clause are determined

// size of buffer

// number of blocks

// rest of bytes after the final block of bytes

if (file.Length < 4096)

{

bufsz = (int)file.Length;

blocks = 1;

}

else

{

bufsz = 4096;

blocks = file.Length / bufsz;

rest = (int)file.Length % bufsz;

}

 

fromFile = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

binReader = new BinaryReader(fromFile);

while ((block <= blocks) && (Response.IsClientConnected))

{

Response.BinaryWrite(binReader.ReadBytes(bufsz));

Response.Flush();

block++;

};

Response.BinaryWrite(binReader.ReadBytes(rest));

if (block * bufsz + rest == file.Length)

{

Response.End();

// Close BinaryReader and FileStream

binReader.Close();

fromFile.Close();

return true;

}

return false;

}

catch

{

Response.End();

// Close BinaryReader and FileStream

binReader.Close();

fromFile.Close();

return false;

}

finally

{

Response.End();

// Close BinaryReader and FileStream

binReader.Close();

fromFile.Close();

}

}

}

}