Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / CSS

MultiUpload, a smarter file upload server control using AJAX

3.27/5 (9 votes)
20 Dec 2007GPL34 min read 1   1.2K  
An ASP.NET server control inspired from Google mail’s selection of file attachments, and implementing ASP.NET AJAX Extensions 1.0.

MultiUpload2 in run mode

Introduction

The HTML file input control and the ASP.NET FileUpload control derived from it have important limitations including poor graphic design and security restrictions. Our objective is to provide a better file upload component. This function is fulfilled by a MultiUpload control, which improves on Google mail’s file attachment experience. Our environment is ASP.NET 2.0 on Windows and IIS, and our MultiUpload control uses ASP.NET AJAX Extensions 1.0, which you can download and install from here.

Background

This article refers to the open-source controls of “Memba Velodoc XP Edition”, which you can download from here (this page provides links to Codeplex, Google code, and Sourceforge.NET) and which are distributed under the GPL license. These controls include a MultiUpload control which we use in this article. You can experiment these controls live at this link.

Using the code

In Visual Studio 2005, create a new ASP.NET AJAX-Enabled Web Site, and add a reference to Memba.WebControls.XP.dll which contains the MultiUpload and MultiUpload2 server controls. Memba.WebControls.XP.dll is part of Memba Velodoc XP Edition. The source code is available at the download location cited above.

MultiUpload and MultiUpload2 expose the same properties and methods. Only the implementation is different:

  1. MultiUpload was our first attempt to execute this control based on an anchor tag. Clicking the anchor tag triggers a Click event on an invisible file input control. Unfortunately, file inputs do not implement the Click method in Firefox, so this control only works in Internet Explorer.
  2. MultiUpload2 is our second attempt to execute this control. MultiUpload2 is a span tag with a file input positioned on top of it. Note that the span tag could easily be replaced by a button or an image. The opacity of the file input is set to 0 so that it is invisible, but can receive the Click event on the Browse button. Each time a file input is filled, it is moved to a hidden location and replaced by a new one in order to permit multiple uploads.

Open the Default.aspx page and add the MultiUpload2 server control, either by dragging and dropping the control after adding it to the toolbox, or simply by adding the following code between the existing <form> tags:

ASP.NET
<form id="form1" runat="server" enctype="multipart/form-data">
<asp:ScriptManager ID="ScriptManager" runat="server" />
<!-- MultiUpload2 -->
<mbui:MultiUpload2 ID="MultiUpload" runat="server"
    Text="Click me"
    CssClass="cssMultiUpload"
    HoverCssClass="cssHoverMultiUpload">
</mbui:MultiUpload2>
<!-- MultiUpload2 -->
<hr />
<div id="divDisplay" style="min-height:50px;">
    <asp:Literal ID="litDisplay" runat="server"></asp:Literal>
</div>
<asp:Button ID="btnSubmit" runat="server" Text="Submit" OnClick="btnSubmit_Click" />
</form>

The form also includes a div (divDisplay) containing an ASP.NET Literal (litDisplay) and an ASP.NET submit button (btnSubmit).

You may have to register the tag prefix at the top of the page, using the following statement:

ASP.NET
<%@ Register Assembly="Memba.WebControls.XP" 
    Namespace="Memba.WebControls" TagPrefix="mbui" %>

For file uploads to work, you need to make two important settings:

  1. Define enctype="multipart/form-data" on the form tag;
  2. Add an httpRuntime section to the <system.web> section of your web.config, with the following attributes:
XML
<httpRuntime maxRequestLength="1000000" executionTimeout="20000"/> 

maxRequestLength defines the maximum size of the post request in kilobytes. The ASP.NET default is 4096, which limits the size of a post request to 4 MB. executionTimeout defines the maximum duration of a request in seconds. It is advised to limit such settings to specific pages, using <location> sections in web.config.

From the standpoint of presentation, the MultiUpload2 control is a SPAN. Add the following styles just above the </head> closing tag of your page:

HTML
<style type="text/css">
<!--
.cssMultiUpload{
color:CornflowerBlue;
text-decoration:none;
}
.cssHoverMultiUpload{
color:CornflowerBlue;
text-decoration:underline;
}
//-->
</style>

Your MultiUpload2 control should now look like:

MultiUpload2 in design mode

Now that our page is designed, we need the code to save the posted files. Double click the Submit button (btnSubmit) to implement the server-side Click event handler in Default.aspx.cs:

C#
private const string TARGET_DIR = "~/";

protected void btnSubmit_Click(object sender, EventArgs e)
{
    //Check target directory
    string sTargetDir = Request.MapPath(TARGET_DIR);
    System.Diagnostics.Debug.Assert(Directory.Exists(sTargetDir));
    StringBuilder objDisplay = new StringBuilder();
    objDisplay.Append("<h3>You have just saved:</h3><ul>");
    //Iterate through posted files (foreach does not work with empty file inputs)
    for (int i = 0; i < Request.Files.Count; i++)
    {
        HttpPostedFile objFile = Request.Files[i];
        //Make sure file input has content
        if ((objFile.ContentLength > 0) && (objFile.FileName.Length > 0))
        {
            //Get target file path for save as
            string sFileName = Path.GetFileName(objFile.FileName);
            string sFilePath = Path.Combine(sTargetDir, sFileName);
            FileInfo objFileInfo = new FileInfo(sFilePath);
            //No business rule, i.e. we just want to avoid failure
            if (objFileInfo.Exists)
            {
                objFileInfo.Attributes &= ~FileAttributes.ReadOnly;
                objFileInfo.Delete();
            }
            //Save file
            objFile.SaveAs(sFilePath);
            //Append link
            objDisplay.AppendFormat("<li><a href=\"{0}\">{1}</a></li>",
            this.ResolveUrl(Path.Combine(TARGET_DIR, sFileName)), sFileName);
        }
    }
    //Display in DIV
    objDisplay.Append("</ul>");
    litDisplay.Text = objDisplay.ToString();
}

Add the following statements at the top of Default.aspx.cs:

C#
using System.IO; //Directory, Path, FileInfo
using System.Text; //StringBuilder

Press F5 to run the page, click the MultiUpload control labeled “Click me” to add a file, and click the Submit button. The response should display links to download the files which have just been uploaded.

We would now like to display the names of the files as they are selected. Add the following script just before the </body> closing tag of your page.

JavaScript
<script type="text/javascript">
<!--
// Declare global variables for the various controls
var g_MultiUpload;
var g_Display = "<h3>You have selected:</h3><ul>";
//pageLoad function of ASP.NET Ajax Extensions framework
function pageLoad()
{
    //Get a reference to the MultiUpload control
    g_MultiUpload = $find("<%= MultiUpload.ClientID %>");
    //Add en event handler for the browse event
    if(g_MultiUpload)
        g_MultiUpload.add_browse(onBrowse);
}
//pageUnload function of ASP.NET Ajax Extensions framework
function pageUnload()
{
    if(g_MultiUpload)
        g_MultiUpload.remove_browse(onBrowse);
}
//Event handler for the browse (click) event of the MultiUpload control
function onBrowse(sender, args)
{
    g_Display += "<li>" + args.get_value() + "</li>";
    $get("divDisplay").innerHTML = g_Display + "</ul>"; 
}
//-->
</script>

ASP.NET AJAX Extensions provide two important JavaScript event handlers:

  • pageLoad is called by the framework when the page DOM and scripts are loaded and initialized. This is a good place to get references to controls and add event handlers.
  • pageUnload is called by the framework when the page unloads. It is recommended to clear handlers at this stage.

The script above implements an event handler for the browse event of the MultiUpload control. The browse event handler adds the full name of the selected file to an unordered list which is displayed within the divDisplay DIV.

Press F5 to run the project, and click the MultiUpload control labeled “Click me” to add a file. The page should now display a list of files as they are selected.

We would now want to interact with the list of selected files, especially to remove files, but this is the subject of a follow-up article entitled Professional file uploads with the MultiUpload and ImageList server controls.

Points of interest

This MultiUpload control hides the complexity of dynamically creating file input HTML controls, and removes any constraint regarding the presentation of the files which have been selected for upload. For more advanced developers, the source code of the MultiUpload control is available at Codeplex, Google code, and Sourceforge.NET, and is commented in great details.

History

  • Version 1.0 - dated 19 Dec 2007

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)