Introduction
This article describes three different approaches to uploading a file to a web server. The approaches are:
- Upload files directly to the server
- Upload files through a web service
- Upload files asynchronously through a web service
This article and included example code describe and illustrate each of these approaches. The examples will illustrate an approach to classifying files upon upload and directing the file to specific folders based upon the type of file uploaded.

Figure 1: File Upload Example Website
Getting Started
In order to get started, unzip the included source code. Within the zip file, you will note that there are two separate projects, one is the web site itself, and the other one is a web service used to upload files. Create virtual directories for the website and the web service, and then add both to a solution within the Visual Studio 2005 IDE.
Both projects should be contained within a single solution in order to make it easier to read and manipulate the projects simultaneously.
The Code: Web Service
The purpose of the web service is to manage file uploads to a collection of folders located in the server�s path. The declarations and imports are all standard to the default template, except for the import used to pull in the System.IO
library; System.IO
is used to capture the file extension from inbound file upload.
Imports System.Web
Imports System.Web.Services
Imports System.Web.Services.Protocols
Imports System.IO
<WebService(Namespace:="http://tempuri.org/")> _
<WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Public Class FileStorage
Inherits System.Web.Services.WebService
The class FileStorage
exposes two web methods: SaveFile
and SaveFileAsType
. SaveFile
is used to save an inbound file, without an extension, into a specific folder, while SaveFileAsType
is used to save the inbound file, with its extension intact, and into specific folders used to hold different types of files (e.g., images or text).
The code for the SaveFile
web method is as follows:
<WebMethod()> _
Public Function SaveFile(ByVal sFileName As String, _
ByVal bytFileByteArr As Byte()) As Integer
Dim strFile As String = _
System.IO.Path.GetFileNameWithoutExtension(sFileName)
strFile = System.Web.Hosting.HostingEnvironment.MapPath _
("~/StorageStuff/" & strFile)
Try
Dim stream As New FileStream(strFile, FileMode.CreateNew)
stream.Write(bytFileByteArr, 0, bytFileByteArr.Length)
stream.Close()
Return 0
Catch ex As Exception
Return 1
End Try
End Function
In examining the code, you will see that the method accepts a String
used to contain the file name, and a Byte
array which carries the content of the file itself. The method strips the file extension from the file name, and defines a new path for the file; you will see that files with anonymous file types are passed to a trash can folder called StorageStuff.
Once the new path is defined and the file extension stripped from the file name, a file stream is created, and the entire byte array containing the file is then passed to the stream. Upon instantiating the file stream, the path defined previously is used to define the file name and the storage location on the server. Once the byte array is written to the file location, the stream is closed, and the method returns a 0 indicating success. If a failure occurs, the exception will be caught, and the method will return a one indicating that the upload failed.
The second web method defined is entitled SaveFileAsType
; this method is used to determine the file type passed into the method, and to place the file into specific folders based upon that file type. The code for that web method is as follows:
<WebMethod()> _
Public Function SaveFileAsType(ByVal sFileName As String, _
ByVal bytFileByteArr As Byte()) As Integer
Dim sFileType As String
sFileType = System.IO.Path.GetExtension(sFileName)
sFileType = sFileType.ToLower()
Select Case sFileType
Case ".doc"
Dim strFile As String = _
System.IO.Path.GetFileNameWithoutExtension(sFileName)
strFile = System.Web.Hosting.HostingEnvironment.MapPath _
("~/StoredText/" & strFile & sFileType)
Try
Dim stream As New FileStream(strFile,
FileMode.OpenOrCreate)
stream.Write(bytFileByteArr, 0, bytFileByteArr.Length)
stream.Close()
Return 0
Catch ex As Exception
Return 1
End Try
Case ".docx"
Dim strFile As String = _
System.IO.Path.GetFileNameWithoutExtension(sFileName)
strFile = System.Web.Hosting.HostingEnvironment.MapPath _
("~/StoredText/" & strFile & sFileType)
Try
Dim stream As New FileStream(strFile,
FileMode.OpenOrCreate)
stream.Write(bytFileByteArr, 0, bytFileByteArr.Length)
stream.Close()
Return 0
Catch ex As Exception
Return 1
End Try
Case ".xml"
Dim strFile As String = _
System.IO.Path.GetFileNameWithoutExtension(sFileName)
strFile = System.Web.Hosting.HostingEnvironment.MapPath _
("~/StoredText/" & strFile & sFileType)
Try
Dim stream As New FileStream(strFile,
FileMode.OpenOrCreate)
stream.Write(bytFileByteArr, 0, bytFileByteArr.Length)
stream.Close()
Return 0
Catch ex As Exception
Return 1
End Try
Case ".rtf"
Dim strFile As String = _
System.IO.Path.GetFileNameWithoutExtension(sFileName)
strFile = System.Web.Hosting.HostingEnvironment.MapPath _
("~/StoredText/" & strFile & sFileType)
Try
Dim stream As New FileStream(strFile,
FileMode.OpenOrCreate)
stream.Write(bytFileByteArr, 0, bytFileByteArr.Length)
stream.Close()
Return 0
Catch ex As Exception
Return 1
End Try
Case ".lic"
Dim strFile As String = _
System.IO.Path.GetFileNameWithoutExtension(sFileName)
strFile = System.Web.Hosting.HostingEnvironment.MapPath _
("~/StoredText/" & strFile & sFileType)
Try
Dim stream As New FileStream(strFile,
FileMode.OpenOrCreate)
stream.Write(bytFileByteArr, 0, bytFileByteArr.Length)
stream.Close()
Return 0
Catch ex As Exception
Return 1
End Try
Case ".txt"
Dim strFile As String = _
System.IO.Path.GetFileNameWithoutExtension(sFileName)
strFile = System.Web.Hosting.HostingEnvironment.MapPath _
("~/StoredText/" & strFile & sFileType)
Try
Dim stream As New FileStream(strFile,
FileMode.OpenOrCreate)
stream.Write(bytFileByteArr, 0, bytFileByteArr.Length)
stream.Close()
Return 0
Catch ex As Exception
Return 1
End Try
Case ".html"
Dim strFile As String = _
System.IO.Path.GetFileNameWithoutExtension(sFileName)
strFile = System.Web.Hosting.HostingEnvironment.MapPath _
("~/StoredText/" & strFile & sFileType)
Try
Dim stream As New FileStream(strFile,
FileMode.OpenOrCreate)
stream.Write(bytFileByteArr, 0, bytFileByteArr.Length)
stream.Close()
Return 0
Catch ex As Exception
Return 1
End Try
Case ".htm"
Dim strFile As String = _
System.IO.Path.GetFileNameWithoutExtension(sFileName)
strFile = System.Web.Hosting.HostingEnvironment.MapPath _
("~/StoredText/" & strFile & sFileType)
Try
Dim stream As New FileStream(strFile,
FileMode.OpenOrCreate)
stream.Write(bytFileByteArr, 0, bytFileByteArr.Length)
stream.Close()
Return 0
Catch ex As Exception
Return 1
End Try
Case ".bmp"
Dim strFile As String = _
System.IO.Path.GetFileNameWithoutExtension(sFileName)
strFile = System.Web.Hosting.HostingEnvironment.MapPath _
("~/StoredImages/" & strFile & sFileType)
Try
Dim stream As New FileStream(strFile,
FileMode.OpenOrCreate)
stream.Write(bytFileByteArr, 0, bytFileByteArr.Length)
stream.Close()
Return 0
Catch ex As Exception
Return 1
End Try
Case ".jpg"
Dim strFile As String = _
System.IO.Path.GetFileNameWithoutExtension(sFileName)
strFile = System.Web.Hosting.HostingEnvironment.MapPath _
("~/StoredImages/" & strFile & sFileType)
Try
Dim stream As New FileStream(strFile,
FileMode.OpenOrCreate)
stream.Write(bytFileByteArr, 0, bytFileByteArr.Length)
stream.Close()
Return 0
Catch ex As Exception
Return 1
End Try
Case ".gif"
Dim strFile As String = _
System.IO.Path.GetFileNameWithoutExtension(sFileName)
strFile = System.Web.Hosting.HostingEnvironment.MapPath _
("~/StoredImages/" & strFile & sFileType)
Try
Dim stream As New FileStream(strFile,
FileMode.OpenOrCreate)
stream.Write(bytFileByteArr, 0, bytFileByteArr.Length)
stream.Close()
Return 0
Catch ex As Exception
Return 1
End Try
Case ".png"
Dim strFile As String = _
System.IO.Path.GetFileNameWithoutExtension(sFileName)
strFile = System.Web.Hosting.HostingEnvironment.MapPath _
("~/StoredImages/" & strFile & sFileType)
Try
Dim stream As New FileStream(strFile,
FileMode.OpenOrCreate)
stream.Write(bytFileByteArr, 0, bytFileByteArr.Length)
stream.Close()
Return 0
Catch ex As Exception
Return 1
End Try
Case ".tif"
Dim strFile As String = _
System.IO.Path.GetFileNameWithoutExtension(sFileName)
strFile = System.Web.Hosting.HostingEnvironment.MapPath _
("~/StoredImages/" & strFile & sFileType)
Try
Dim stream As New FileStream(strFile,
FileMode.OpenOrCreate)
stream.Write(bytFileByteArr, 0, bytFileByteArr.Length)
stream.Close()
Return 0
Catch ex As Exception
Return 1
End Try
Case ".ico"
Dim strFile As String = _
System.IO.Path.GetFileNameWithoutExtension(sFileName)
strFile = System.Web.Hosting.HostingEnvironment.MapPath _
("~/StoredImages/" & strFile & sFileType)
Try
Dim stream As New FileStream(strFile,
FileMode.OpenOrCreate)
stream.Write(bytFileByteArr, 0, bytFileByteArr.Length)
stream.Close()
Return 0
Catch ex As Exception
Return 1
End Try
Case ".wmf"
Dim strFile As String = _
System.IO.Path.GetFileNameWithoutExtension(sFileName)
strFile = System.Web.Hosting.HostingEnvironment.MapPath _
("~/StoredImages/" & strFile & sFileType)
Try
Dim stream As New FileStream(strFile,
FileMode.OpenOrCreate)
stream.Write(bytFileByteArr, 0, bytFileByteArr.Length)
stream.Close()
Return 0
Catch ex As Exception
Return 1
End Try
Case Else
Dim strFile As String = _
System.IO.Path.GetFileNameWithoutExtension(sFileName)
strFile = System.Web.Hosting.HostingEnvironment.MapPath _
("~/StorageStuff/" & strFile & sFileType)
Try
Dim stream As New FileStream(strFile,
FileMode.OpenOrCreate)
stream.Write(bytFileByteArr, 0, bytFileByteArr.Length)
stream.Close()
Return 0
Catch ex As Exception
Return 1
End Try
End Select
End Function
The code is pretty straightforward, the inbound file�s extension is captured and used within a Select Case
statement. The Select Case
statement filters the files by the extension, and then writes them out into specific folders depending upon the file type (images, text, or unknown file types).
The process used to write out the file is the same used in the first web method discussed. In each case, the attempt to write the file is wrapped in a Try � Catch
block; if the file write is successful, the method returns a 0, and if the attempt fails, the method returns a 1. The returned value is used by the calling method to determine whether or not the method succeeded or failed. Note: If the file has already been uploaded to the server, the method will not overwrite the file and it will return a failure indication.
The Code: Web Site
The web site offers the user several alternatives for uploading a file:
- Upload a file directly to the web site server
- Upload a file through a web service with the file extension stripped off
- Upload a file asynchronously through a web service with the extension stripped off
- Upload a file through a web service with the extension intact
- Upload a file asynchronously through a web service with the extension intact
The default ASPX page contains all of the methods used in support of the web site, and is the only page on the site. The default page imports the System IO library in order to perform manipulations involving the file extension.
The class declaration is standard, and inherits from the
Page
class. Only one object is declared with page level scope, and that object is the proxy for the web service described previously. It is not necessary to give the proxy page-wide scope, but it does not harm anything to do so, and it saves some coding within the individual methods.
The initial part of the site�s default page code is as follows:
Imports System.IO
Partial Class _Default
Inherits System.Web.UI.Page
Private ws As New FileStorage.FileStorage()
The first method coded in the default page is the handler for the button used to load a file directly onto the web server. The subroutine used for this purpose first checks to see if the associated file upload control has a file associated with it and, if it does, it captures the extension of that file. The file extension is used to determine how the file will be processed (primarily to determine whether or not the file is an image or a text document, and subsequently to write the file to the appropriate folder). Files that cannot be classified within the Select Case
statement are dumped into a trash can folder.
The code for this subroutine is as follows:
Protected Sub btnUpload_Click(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles btnUpload.Click
Try
control
If FileUpload1.HasFile Then
Dim sFileType As String
sFileType = System.IO.Path.GetExtension(FileUpload1.FileName)
sFileType = sFileType.ToLower()
Select Case sFileType
Case ".doc"
FileUpload1.SaveAs(MapPath("~/UploadedText/" & _
FileUpload1.FileName.ToString()))
Case ".docx"
FileUpload1.SaveAs(MapPath("~/UploadedText/" & _
FileUpload1.FileName.ToString()))
Case ".xml"
FileUpload1.SaveAs(MapPath("~/UploadedText/" & _
FileUpload1.FileName.ToString()))
Case ".rtf"
FileUpload1.SaveAs(MapPath("~/UploadedText/" & _
FileUpload1.FileName.ToString()))
Case ".lic"
FileUpload1.SaveAs(MapPath("~/UploadedText/" & _
FileUpload1.FileName.ToString()))
Case ".txt"
FileUpload1.SaveAs(MapPath("~/UploadedText/" & _
FileUpload1.FileName.ToString()))
Case ".html"
FileUpload1.SaveAs(MapPath("~/UploadedText/" & _
FileUpload1.FileName.ToString()))
Case ".htm"
FileUpload1.SaveAs(MapPath("~/UploadedText/" & _
FileUpload1.FileName.ToString()))
Case ".bmp"
FileUpload1.SaveAs(MapPath("~/UploadedPictures/" & _
FileUpload1.FileName.ToString()))
Case ".jpg"
FileUpload1.SaveAs(MapPath("~/UploadedPictures/" & _
FileUpload1.FileName.ToString()))
Case ".gif"
FileUpload1.SaveAs(MapPath("~/UploadedPictures/" & _
FileUpload1.FileName.ToString()))
Case ".png"
FileUpload1.SaveAs(MapPath("~/UploadedPictures/" & _
FileUpload1.FileName.ToString()))
Case ".tif"
FileUpload1.SaveAs(MapPath("~/UploadedPictures/" & _
FileUpload1.FileName.ToString()))
Case ".ico"
FileUpload1.SaveAs(MapPath("~/UploadedPictures/" & _
FileUpload1.FileName.ToString()))
Case ".wmf"
FileUpload1.SaveAs(MapPath("~/UploadedPictures/" & _
FileUpload1.FileName.ToString()))
Case Else
FileUpload1.SaveAs(MapPath("~/UploadedStuff/" & _
FileUpload1.FileName.ToString()))
End Select
MessageBox("File uploaded to web server.")
End If
Catch ex As Exception
MessageBox(ex.Message.ToString())
End Try
End Sub
The subroutine is contained within a Try � Catch
block, and if the file is processed correctly, the user is notified that the file was uploaded successfully. If the file fails to upload, the user is shown an alert box with the exception�s message printed out.
The next method in the class is the button click handler used to upload a file through a web service; this handler does not evoke the web service web method asynchronously, and it will show an alert when the file has been uploaded through the web service. As this handler calls the web service's SaveFile
web method, files uploaded with this option will be saved onto the web service�s server without a file extension. If the subroutine fails, the exception�s message will be displayed in an alert box.
Protected Sub btnUploadSyncToWS_Click(ByVal sender As Object, _
ByVal e As System.EventArgs) _
Handles btnUploadSyncToWS.Click
Try
If FileUpload2.HasFile Then
Dim bytes As Byte() = FileUpload2.FileBytes
ws.SaveFile(FileUpload2.FileName.ToString(), bytes)
MessageBox("File Upload completed")
End If
Catch ex As Exception
MessageBox(ex.Message.ToString())
End Try
End Sub
The next method in the default page class is used to upload a file through a web service with an intact file extension. The code for this subroutine is nearly identical to the last subroutine, but rather than calling the SaveFile
method, the subroutine calls the web service's SaveFileAsType
method. The code for this method is as follows:
Protected Sub btnToWSwithExtension_Click(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles btnToWSwithExtension.Click
Try
If FileUpload3.HasFile Then
Dim bytes As Byte() = FileUpload3.FileBytes
ws.SaveFileAsType(FileUpload3.FileName.ToString(), bytes)
MessageBox("File Upload completed")
End If
Catch ex As Exception
MessageBox(ex.Message.ToString())
End Try
End Sub
The next subroutine is a little more interesting in that it calls upon the web service to upload a file asynchronously. This subroutine does not use a callback, and it does implement a wait handle to block the page from loading until after the results are returned from the web service; the subroutine then processes the result, and displays an indication of success or failure to the user, depending upon the result returned from the web service. I chose to handle the subroutine in this manner for the sake of simplicity. If you want to process the results in some other manner, and are not concerned about blocking the page load, you should implement a callback and process the results in the callback. Since I wanted to display a message to the user when the task completed, this was a reasonable option to adopt.
Note that, in this subroutine, the results are set to the web service proxy�s BeginSaveFile
method, rather than the SaveFile
method manually coded within the web service project. A wait handle is also set, and the results are only processed after the method returns. If you were to implement a callback, you would initiate a callback in this method, set it to point at a custom handler added to this class, add the callback to the argument list for the BeginSaveFile
method call (third argument), and then process the results in that handler.
The BeginSaveFile
method called does the same thing the SaveFile
method does in that it strips the file extension off of the file name and places the file into a trash can folder on the web service�s server.
Protected Sub btnUploadNoExtAsync_Click(ByVal sender As Object, _
ByVal e As System.EventArgs) _
Handles btnUploadNoExtAsync.Click
Try
If FileUpload2.HasFile Then
Dim bytes As Byte() = FileUpload2.FileBytes
from
Dim iaresult As IAsyncResult
iaresult = ws.BeginSaveFile(FileUpload2.FileName.ToString(),
bytes, Nothing, Nothing)
iaresult.AsyncWaitHandle.WaitOne()
Dim rtnVal As String
rtnVal = ws.EndSaveFile(iaresult)
If rtnVal = "0" Then
MessageBox("File uploaded")
Else
MessageBox("File upload failed")
End If
End If
Catch ex As Exception
MessageBox(ex.Message.ToString())
End Try
End Sub
The next subroutine coded in the default page class is used to perform an asynchronous file upload which retains the file�s extension. The code for this subroutine is nearly identical to the previous subroutine, but it calls the BeginSaveFileAsType
method instead of the BeginSaveFile
method used in the last subroutine. That code is as follows:
Protected Sub btnUploadWithExtAsync_Click(ByVal sender As Object, _
ByVal e As System.EventArgs) _
Handles btnUploadWithExtAsync.Click
Try
If FileUpload3.HasFile Then
Dim bytes As Byte() = FileUpload3.FileBytes
from
Dim iaresult As IAsyncResult
iaresult =
ws.BeginSaveFileAsType(FileUpload3.FileName.ToString(), _
bytes, Nothing, Nothing)
iaresult.AsyncWaitHandle.WaitOne()
Dim rtnVal As String
rtnVal = ws.EndSaveFileAsType(iaresult)
If rtnVal = "0" Then
MessageBox("File uploaded")
Else
MessageBox("File upload failed")
End If
End If
Catch ex As Exception
MessageBox(ex.Message.ToString())
End Try
End Sub
The last bit of code in the default page class is used to generate the message boxes used to display the status information to the user. Since we cannot realistically add an OnClick
event to one of the controls after the event has fired before we know the status, this code displays the results by adding a label to the form and putting the JavaScript necessary to fire an alert box off, with the status message passed into the alert box. Given the Label
control will process any HTML it receives, you can pass the JavaScript to the control and execute it by adding the control to the page. That code is as follows:
Private Sub MessageBox(ByVal strMsg As String)
Dim lbl As New Label
lbl.Text = "<script language="
& "window.alert(" & "'" & strMsg & "'" & ")</script>"
Page.Controls.Add(lbl)
End Sub
Summary
This article discussed an approach to uploading files to a web server directly through an ASPX page, or through a web service. Further, the article described some of the methods used to asynchronously upload files using a simplified approach. Other methods exist for asynchronously uploading files (or executing any web service web method asynchronously), but the best option to use is based upon factors such as whether or not you need to provide status and feedback to the user during or after the execution of the method. The purpose of this article was merely to discuss file uploads, and not to address the entire topic of asynchronous method calls.