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

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 VB.NET

Downloading a file from the Web site in VB.NET

 

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=”vb” AutoEventWireup=”true” CodeBehind=”TestDownloadVC.aspx.vb” 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 VB.NET

Imports System

Imports System.Collections.Generic

Imports System.Linq

Imports System.Web

Imports System.Web.UI

Imports System.Web.UI.WebControls

Imports System.IO

 

 

Public Class TestDownloadVB

Inherits 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 Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

Dim files() As String

Dim idx As Integer

‘ Set up the download button event handler

If (Not Page.IsPostBack) Then

‘ 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 To files.Length – 1

files(idx) = New FileInfo(files(idx)).Name

Next

‘ 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

End If

End Sub

 

Protected Sub btnDownload_Click(sender As Object, e As EventArgs) Handles btnDownload.Click

If (Not BufferedDownload()) Then

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

End If

End Sub

‘ 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 Function BufferedDownload() As Boolean

Dim file As FileInfo

Dim filename As String

Dim fromFile As FileStream

Dim binReader As BinaryReader

 

‘ 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 (Not file.Exists) Then

System.Web.UI.ScriptManager.RegisterStartupScript(Me, Me.GetType(), “FileNotFoundWarning”, “alert(‘File is not available now!’)”, True)

BufferedDownload = False

End If

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

Dim bufsz As Integer = 0    ‘ size of buffer

Dim block As Long = 1       ‘ block of bytes

Dim blocks As Long = 0      ‘ number of blocks of bytes

Dim rest As Integer = 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) Then

bufsz = CInt(file.Length)

blocks = 1

Else

bufsz = 4096

blocks = file.Length / bufsz

rest = CInt(file.Length Mod bufsz)

End If

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

binReader = New BinaryReader(fromFile)

While ((block <= blocks) And (Response.IsClientConnected))

Response.BinaryWrite(binReader.ReadBytes(bufsz))

Response.Flush()

block = block + 1

End While

Response.BinaryWrite(binReader.ReadBytes(rest))

If (block * bufsz + rest = file.Length) Then

Response.End()

‘ Close BinaryReader and FileStream

binReader.Close()

fromFile.Close()

BufferedDownload = True

End If

BufferedDownload = False

Catch ex As Exception

Response.End()

‘ Close BinaryReader and FileStream

binReader.Close()

fromFile.Close()

BufferedDownload = False

Finally

Response.End()

‘ Close BinaryReader and FileStream

binReader.Close()

fromFile.Close()

End Try

 

End Function

End Class