
Introduction
I will briefly demonstrate how to upload multiple files using one HttpInputFile
control - Hotmail style! Many developers have been asking how to upload
multiple files at once. The <Input type=file/>
allows a
user to select only one file at a time thereby forcing a developer to use
multiple <Input type=file/>
on a page.
Background
This article is a repost of an article that I posted here about a week ago. There
was a bug in the first article so I took it down after explaining the bug. If you
missed the explanation here is a summary. The HttpInputControl
control
does not allow for the PostedFile
value to be set at runtime. If that
were the case then anyone could set a <Input type=file/>
value
with the name of a file that is on the client and download it. So this is by design that
the value can not be set. I attempted to store the values of the selected files in a listbox
and then pass those values to the HttpInputControl
. In my rush to post
I did not notice that empty files were being saved to the web server. So here is my second
and I hope final attempt at demonstrating how to upload multiple files to a web server while
using only one HttpInputControl
control.
Using the code
Using this code could not get any simpler. It's almost to easy thanks to .NET!
First there is my style sheet, StyleSheet.css. I am fond of the colored flat
buttons so I created a style called 'bluebutton'. Next is the .aspx page,
attachme.aspx followed by the code-behind attachme.aspx.cs.
My style sheet code for StyleSheet.css:
.bluebutton
{
background-color:LightSteelBlue;
border-style:solid;
border-width: 1px;
border-color: LightSkyBlue;
}
Now here is the code for attachme.aspx.
<%@ Page language="c#" Codebehind="attachme.aspx.cs" AutoEventWireup="false"
Inherits="webchange.attachme" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
<title>attachme</title>
<meta content="Microsoft Visual Studio 7.0" name="GENERATOR">
<meta content="C#" name="CODE_LANGUAGE">
<meta content="JavaScript" name="vs_defaultClientScript">
<meta content="http://schemas.microsoft.com/intellisense/ie5"
name="vs_targetSchema">
<LINK href="StyleSheet.css" rel="stylesheet">
</HEAD>
<body MS_POSITIONING="GridLayout">
<form id="attachme" method="post" encType="multipart/form-data" runat="server">
<INPUT class="bluebutton" id="FindFile" style="Z-INDEX: 101; LEFT: 36px;
WIDTH: 274px; POSITION: absolute; TOP: 123px; HEIGHT: 22px"
type="file" size="26" runat="server" NAME="FindFile">
<asp:listbox id="ListBox1" style="Z-INDEX: 102; LEFT: 36px;
POSITION: absolute; TOP: 149px" runat="server" CssClass="txtbox"
Height="100px" Width="274px" Font-Size="XX-Small"></asp:listbox>
<asp:button id="AddFile" style="Z-INDEX: 103; LEFT: 34px; POSITION: absolute;
TOP: 254px" runat="server" CssClass="bluebutton" Height="23px"
Width="72px" Text="Add"></asp:button>
<asp:button id="RemvFile" style="Z-INDEX: 104; LEFT: 119px;
POSITION: absolute; TOP: 255px" runat="server"
CssClass="bluebutton"
Height="23px" Width="72px" Text="Remove"></asp:button>
<INPUT class="bluebutton" id="Upload" style="Z-INDEX: 105; LEFT: 236px;
WIDTH: 71px; POSITION: absolute; TOP: 254px; HEIGHT: 24px"
type="submit" value="Upload" runat="server"
onserverclick="Upload_ServerClick" NAME="Upload">
</form>
<asp:label id="Label1" style="Z-INDEX: 106; LEFT: 46px; POSITION: absolute;
TOP: 326px" runat="server" Height="25px"
Width="249px"></asp:label></span>
</body>
</HTML>
And last but not least is the codebehind - attachme.aspx.cs The code-behind is
very straightforward. AddFile_Click
, RemvFile_Click
and
Upload_ServerClick
are the three functions that are called.
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Xml;
namespace webchange
{
public class attachme : System.Web.UI.Page
{
protected System.Web.UI.WebControls.ListBox ListBox1;
protected System.Web.UI.WebControls.Button AddFile;
protected System.Web.UI.WebControls.Button RemvFile;
protected System.Web.UI.HtmlControls.HtmlInputFile FindFile;
protected System.Web.UI.HtmlControls.HtmlInputButton Upload;
protected System.Web.UI.WebControls.Label Label1;
protected System.Web.UI.HtmlControls.HtmlGenericControl txtOutput;
public ArrayList files = new ArrayList();
static public ArrayList hif = new ArrayList();
public int filesUploaded = 0;
private void Page_Load(object sender, System.EventArgs e)
{
}
#region Web Form Designer generated code
override protected void OnInit(EventArgs e)
{
InitializeComponent();
base.OnInit(e);
}
private void InitializeComponent()
{
this.RemvFile.Click += new System.EventHandler(this.RemvFile_Click);
this.AddFile.Click += new System.EventHandler(this.AddFile_Click);
this.Upload.ServerClick += new System.EventHandler(this.Upload_ServerClick);
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion
private void AddFile_Click(object sender, System.EventArgs e)
{
if (Page.IsPostBack == true)
{
hif.Add(FindFile);
ListBox1.Items.Add(FindFile.PostedFile.FileName);
}
else
{
}
}
private void RemvFile_Click(object sender, System.EventArgs e)
{
if(ListBox1.Items.Count != 0)
{
hif.RemoveAt(ListBox1.SelectedIndex);
ListBox1.Items.Remove(ListBox1.SelectedItem.Text);
}
}
public void Upload_ServerClick(object sender, System.EventArgs e)
{
string baseLocation = "C:\\temp\\";
string status = "";
if((ListBox1.Items.Count == 0) && (filesUploaded == 0))
{
Label1.Text = "Error - a file name must be specified.";
return;
}
else
{
foreach(System.Web.UI.HtmlControls.HtmlInputFile HIF in hif)
{
try
{
string fn = System.IO.Path.GetFileName(HIF.PostedFile.FileName);
HIF.PostedFile.SaveAs(baseLocation + fn);
filesUploaded++;
status += fn + "<br>";
}
catch(Exception err)
{
Label1.Text = "Error saving file " + baseLocation
+ "<br>" + err.ToString();
}
}
if(filesUploaded == hif.Count)
{
Label1.Text = "These " + filesUploaded + " file(s) were "
+ "uploaded:<br>" + status;
}
hif.Clear();
ListBox1.Items.Clear();
}
}
}
}
AddFile_Click
first checks to see if we are posting back to the page. If we are
then it simply adds a copy of HttpInputFile FindFile
to the
hifArrayList
. We are using the ArrayList
to hold
HttpInputFile
objects. By holding them, as I will show shortly, we will
have access to all of that object's methods and properties. The final line of
AddFile_Click
adds the fully qualified path of the file to the listbox.
private void AddFile_Click(object sender, System.EventArgs e)
{
if (Page.IsPostBack == true)
{
hif.Add(FindFile);
ListBox1.Items.Add(FindFile.PostedFile.FileName);
}
else
{
}
}
RemvFile_Click
first ensures that there are items in the listbox to
remove, then removes the selected item from the
ArrayList
and the
ListBox
.
private void RemvFile_Click(object sender, System.EventArgs e)
{
if(ListBox1.Items.Count != 0)
{
hif.RemoveAt(ListBox1.SelectedIndex);
ListBox1.Items.Remove(ListBox1.SelectedItem.Text);
}
}
Upload_ServerClick
is the heart of the form. First we set the
destination variable's,
baseLocation
, path.
This is the location on the web server where the file will be uploaded to. Next
we ensure that there are files to be uploaded. Assuming that there are loop
through the items in the
ArrayList hif
extracting the filename from each
path and appending it to the
baseLocation
variable. Call the
SaveAs
method of the
HttpInputFile
control and pass it
the path and filename to upload to the server. Of course we will check for
errors and will handle them accordingly. Lastly explicitly clear the
ArrayList hif
. Since this is a static variable we want to ensure that
its contents have been removed from memory so as not to duplicate and overwrite files on the
server. Clear the listbox. You are done. Check the server to make sure the files
are there and are of the proper size.
public void Upload_ServerClick(object sender, System.EventArgs e)
{
string baseLocation = "C:\\temp\\";
string status = "";
if((ListBox1.Items.Count == 0) && (filesUploaded == 0))
{
Label1.Text = "Error - a file name must be specified.";
return;
}
else
{
foreach(System.Web.UI.HtmlControls.HtmlInputFile HIF in hif)
{
try
{
string fn = System.IO.Path.GetFileName(HIF.PostedFile.FileName);
HIF.PostedFile.SaveAs(baseLocation + fn);
filesUploaded++;
status += fn + "<br>";
}
catch(Exception err)
{
Label1.Text = "Error saving file " + baseLocation + "<br>"
+ err.ToString();
}
}
if(filesUploaded == hif.Count)
{
Label1.Text = "These " + filesUploaded + " file(s) were uploaded:<br>"
+ status;
}
hif.Clear();
ListBox1.Items.Clear();
}
}
Conclusion
There really is no great magic behind this code. In fact it might not even be
the best way to accomplish this. For now though hopefully it will help others
as much as it has helped me.