Upload Multiple Files in ASP.NET

7. November 2008 20:16

Update: 07-18-2011 - since this is an older article..this concept still works but please see my newer post about utilizing Plupload to handle multiple file uploads here

I have seen a lot of different ways to upload multiple files in ASP.NET but they all consisted of either using a lot of javascript, a pre-determined amount of FileUpload controls on the page, or 3rd part controls that will do it for you. I decided to take a different approach and use bytes to utilize multiple files. 

Now this demonstration is actually showing how to upload multiple photos in ASP.NET, but it can very well be used to upload multiple files as well.

The concept is as follows:

One FileUpload control on the page
One DataList to show which images the user will be uploading
Store image information in a dataset with one of the columns being the image in bytes
User has option to remove image from the upload list if they want before uploading it.

I will simply copy and paste the code for what I have done.  I will mention I have not tested this fully in production.  My development Environment is VS 2008, debugging using built in web server in Visual Studio.

This code is for a file called getImage.aspx.  This returns the image in binary for previewing of which images will be uploaded.  You’ll see the main pages uses this page as the ImageUrl in the DataList. I am only pasting the code behind because there isn’t any markup involved.

getImage.aspx.cs

protected void Page_Load(object sender, EventArgs e)
{
 //TODO: error checking for query string

 if(Session["dsPhotoFiles"] != null)
 {
      DataSet tmpDs = new DataSet();
      tmpDs = (DataSet)Session["dsPhotoFiles"];

      for (int i = 0; i < tmpDs.Tables[0].Rows.Count; i++)
      {
         if (tmpDs.Tables[0].Rows[i]["id"].ToString() == Request.QueryString["id"])
         {
             Response.BinaryWrite((byte[])(tmpDs.Tables[0].Rows[i]["fileBytes"]));
             break;
         }
      }
 }
}

 

Below is now the code for the main page used to upload multiple images.

Default.aspx

This is the code inside the form tag

<div>
     <asp:Label ID="Label1" runat="server" Text="Locate File:" />&nbsp;&nbsp;
     <asp:FileUpload ID="fileUp" runat="server" /> &nbsp;&nbsp;
     <br />
     <asp:Label ID="Description" runat="server" Text="Description:"></asp:Label>&nbsp;&nbsp;
     <asp:TextBox ID="txtDesc" runat="server" Width="349px"></asp:TextBox>
     <asp:Button ID="btnAddFile" runat="server" Text="Add File To Upload List"
                onclick="btnAddFile_Click" />
</div>
 
<div>
     <asp:Label ID="lblCurrentFileCount" runat="server"></asp:Label>
     <br />
     <asp:DataList ID="dlPhotoFiles" runat="server" RepeatColumns="10" RepeatDirection="Horizontal">
         <ItemTemplate>
             <asp:Image ID="Image1" runat="server" ImageUrl='<%# string.Format("~/getImage.aspx?id={0}", Eval("id")) %>'
                   Width="50" AlternateText='<%# Eval("fileDesc") %>' />
             <br />
             <asp:LinkButton ID="lnkBtnRemovePhoto" runat="server"
                        CommandArgument='<%# Eval("id") %>' OnCommand="lnkBtnRemovePhoto_Command">Remove</asp:LinkButton>
         </ItemTemplate>                  
      </asp:DataList>
      <br />
</div>
<br />
<div>
     <asp:Button ID="btnUploadFiles" runat="server" Text="Upload File(s)"
                   onclick="btnUploadFiles_Click" />
</div>


Default.aspx.cs

This is all of the code behind:

DataSet dsPhotosFiles = new DataSet();

        protected void Page_Init(object sender, EventArgs e)
        {

            if (Session["dsPhotoFiles"] == null)
            {
                this.initPhotoDS();
                Session.Add("dsPhotoFiles", dsPhotosFiles);
            }
            else
            {
                dsPhotosFiles = (DataSet)Session["dsPhotoFiles"];
            }
        }

        protected void btnAddFile_Click(object sender, EventArgs e)
        {

            if (fileUp.PostedFile.ContentLength > 0)
            {
                //TODO: logic for file extension check
                DataRow dr = dsPhotosFiles.Tables[0].NewRow();

                string fileExt = System.IO.Path.GetExtension(fileUp.PostedFile.FileName);

                byte[] imageBytes = new byte[fileUp.PostedFile.InputStream.Length];
                fileUp.PostedFile.InputStream.Read(imageBytes, 0, imageBytes.Length);

                dr["fileBytes"] = imageBytes;
                dr["filePath"] = fileUp.PostedFile.FileName;
                dr["fileDesc"] = txtDesc.Text;
                dr["id"] = System.Guid.NewGuid().ToString();

                dsPhotosFiles.Tables[0].Rows.Add(dr);
            }

            this.bindDataList();          

            txtDesc.Text = "";
            lblCurrentFileCount.Text = "Current Files To Upload: " + dsPhotosFiles.Tables[0].Rows.Count;
        }

        protected void btnUploadFiles_Click(object sender, EventArgs e)
        {

            try
            {
                for (int i = 0; i < dsPhotosFiles.Tables[0].Rows.Count; i++)
                {
                    //TODO:logic to save image path and description to database
                   
                    string fileName = System.IO.Path.GetFileName(dsPhotosFiles.Tables[0].Rows[i]["filePath"].ToString());

                    byte[] imageBytes;
                    imageBytes = (byte[])dsPhotosFiles.Tables[0].Rows[i]["fileBytes"];

                    //their is no uploading..just writing out the bytes to the directory on the web server.
                    System.IO.File.WriteAllBytes(Server.MapPath(string.Format("~/documents/{0}", fileName)), imageBytes);
                }

                //TODO: show success message logic

                //clear out rows of dataset not the whole dataset
                dsPhotosFiles.Tables[0].Rows.Clear();
                this.bindDataList();
                lblCurrentFileCount.Text = "Current Files To Upload: " + "0";
               
            }
            catch (Exception ex)
            {
                //TODO: show error message of which file did not get uploaded
                throw new Exception(ex.Message);
            }
          
        }

        private void initPhotoDS()
        {
            dsPhotosFiles.Tables.Add("Photos");
            dsPhotosFiles.Tables[0].Columns.Add("fileBytes", Type.GetType("System.Byte[]"));
            dsPhotosFiles.Tables[0].Columns.Add("filePath");
            dsPhotosFiles.Tables[0].Columns.Add("fileDesc");
            dsPhotosFiles.Tables[0].Columns.Add("id");
        }

        private void bindDataList()
        {
            dlPhotoFiles.DataSource = dsPhotosFiles;
            dlPhotoFiles.DataKeyField = "id";
            dlPhotoFiles.DataBind();
        }

        protected void lnkBtnRemovePhoto_Command(object sender, CommandEventArgs e)
        {

            foreach(DataRow dr in dsPhotosFiles.Tables[0].Rows)
            {
                if (dr["id"].ToString() == e.CommandArgument.ToString())
                {
                    dsPhotosFiles.Tables[0].Rows.Remove(dr);
                    break;
                }

            }

            this.bindDataList();
            lblCurrentFileCount.Text = "Current Files To Upload: " + dsPhotosFiles.Tables[0].Rows.Count;
        }

 

Again, I have not tested this fully in product, but it seems to be working very solid right now in my debug environment. 

The one downfall I see to this is that for large photos that could be a lot to store in memory/session.  Now a good thing about this is that it would be very easy to limit the photo/image count a user can upload because you can just check the row count in the dataset and either add it or not to the dataset.

I see a couple of advantages to this:

The image is in memory so their really isn’t any uploading involved because once it’s in memory it’s write it directly to the directy on the web server.
Gives the user the ability to see the photos they are uploading
Gives the user the ability to remove photos before they commit to uploading them
Can write image information to a database if you would like.

As always, I hope this will make it easier for those out their like me who want a decent way to upload multiple files.  Please comment for any bugs found in this.  I will review this over the next couple of days and try in production as well.

Tags:

ASP.NET

blog comments powered by Disqus



My Random Thought

I think the OCW is a great thing to have available to those who are in school, just finished school or just want to educate themself

http://ocwconsortium.org/

John On Twitter

Discounts