Saving Uploaded Files in HTML5/Flash Uploader ASP.NET

Supported technologies: Adobe FlashHTML 5

As you know HTML5/Flash Uploader sends files and additional metadata from client computers to server side in HTTP POST requests. This approach requires server script to parse the received requests and handle uploaded data. Reading this topic you will learn to extract files and additional data sent by clients, save them all to file system on a server or handle in some other way. There are three approaches to perform this task:

  • Uploading files to the specified folder on a server. This is the simplest way, it allows to save all uploaded files almost without coding. However, this method is not flexible enough, so do not use it if you need to get access to additional data (such as information about original files, additional fields, etc.).
  • Extended processing of uploaded data using HTML5/Flash Uploader server-side controls and components. This approach gives you flexible typed access to all data sent from client computers. It suites best for ASP.NET applications because HTML5/Flash Uploader ASP.NET components offer server-side API allowing to accomplish any operation on the uploaded data in a usual for ASP.NET developers way.
  • Parsing POST requests using standard ASP.NET Request object. This method is not different from when you are using form-based file upload in HTML (browse/upload buttons on your page). If you use it, you get untyped access to uploaded data, also this approach does not support automatic assembling files from chunks (in case if you enable them in HTML5/Flash Uploader, of course). The main advantage of this method is that you do not have additional references to Aurigma assemblies in your ASP.NET application.
Note

If you parse requests using the ASP.NET Request object and enable sending files by chunks, you will have to write significant amount of non-trivial server-side code to assembly the files on your server. Thus, we do not recommend enabling chunks if you use this method of handling requests.

Further in this topic every approach will be described in detail. Firstly, let us describe HTML5/Flash Uploader ASP.NET components.

Server-side Components

All the HTML5/Flash Uploader ASP.NET classes and types are located in the Aurigma.ImageUploaderFlash.dll assembly. There are three main ones allowing to process the data uploaded from client computers (ImageUploaderFlash, UploadRequest and UploadHandler). All three of them have similar API and functionality giving flexible typed access to these data. The class to use in your application depends on where you handle the received data:

  • ImageUploaderFlash is a WebForms control. This control can both embed HTML5/Flash Uploader in a web page (e.g. using Microsoft Visual Studio designer) and handle the data being uploaded by HTML5/Flash Uploader from client computers at run-time. Use this component if you host HTML5/Flash Uploader and receive uploads at the same web page. For more information on how to embed HTML5/Flash Uploader in a web page see the Quick Start with HTML5/Flash Uploader ASP.NET topic.
  • UploadRequest is a non-visual WebForms control. It is a right choice if you set up HTML5/Flash Uploader to upload files to a page different from the page where it is hosted. Put UploadRequest component on the page which receives the uploads to handle them.
  • UploadHandler class implements the IHttpHandler interface. If you want to create your own custom HTTP handler (see the HTTP Handlers and HTTP Modules Overview MSDN article) which receives and processes data uploaded from client machines, it is a solution for you. You just need to inherit your .ashx handler from this class and it will automatically parse requests received from HTML5/Flash Uploader and will expose API to access the files and data.
Note

If you use IIS 7.5 you should disable request validation on the page which hosts the component handling upload.

<%@ Page Language="C#" ValidateRequest="false" %>

Uploading Files to Specified Folder

This section describes the simplest way of handling uploaded data - autosave. This approach allows you to save all the uploaded files to the specified folder on your server without writing a lot of code. All server-side components described in the previous section can save uploaded files automatically. You just have to choose the component, plug it in your ASP.NET application and configure the Autosave Uploader.AutoSave UploadRequest.AutoSave UploadHandler.AutoSave and the DestinationFolder Uploader.DestinationFolder UploadRequest.DestinationFolder UploadHandler.DestinationFolder properties. To enable autosave feature set the Autosave Uploader.AutoSave UploadRequest.AutoSave UploadHandler.AutoSave property to true. After that set the DestinationFolder Uploader.DestinationFolder UploadRequest.DestinationFolder UploadHandler.DestinationFolder property to the path to folder where uploaded files are saved. If the specified folder does not exist, HTML5/Flash Uploader will try to create it.

If you need to process the saved files in some way, then a page specified in the UploadSettings.RedirectUrl setting is the right place for this. Just put your code there and it will be executed after the upload process is completed.

The following examples show how to configure autosave for each of the server-side components.

Autosave via Uploader Control

After embedding the ImageUploaderFlash control in your page as it is described in the Quick Start with HTML5/Flash Uploader ASP.NET topic, configure the control like it is shown below:

ASP.NET
<aur:ImageUploaderFlash ID="Uploader1" runat="server" 
    AutoSave="true"
    DestinationFolder="~/Catalog" />

Autosave via UploadRequest Control

In this scenario, you have two pages - one page contains the ImageUploaderFlash control, where you configure the client-side uploader settings. In addition to them, you point out a URL of another .aspx page which accepts the uploaded files using the UploadSettings.ActionUrl property. It should contain the UploadRequest control instance.

The uploader page may look like this:

ASP.NET
<aur:ImageUploaderFlash runat="server">
    <UploadSettings ActionUrl="UploadRequestPage.aspx" />
</aur:ImageUploaderFlash>

The second page should include the UploadRequest as follows:

ASP.NET
<aur:UploadRequest ID="UploadRequest1" runat="server"
    AutoSave="true"
    DestinationFolder="~/Catalog" />

Autosave via UploadHandler Class

Since UploadHandler is not a WebForms control you do not have to create a separate page to host it. You just create a new handler (an .ashx file), which inherits from the UploadHandler. For example, like this one:

C#
public class SimpleHandler : Aurigma.ImageUploaderFlash.UploadHandler
{
    public SimpleHandler ()
    {
        DestinationFolder = "~/Catalog";
        AutoSave = true;
    }
}

And specify a URL to this handler as a value of the UploadSettings.ActionUrl property (both absolute and relative URLs are supported).

Note

If your file storage is located separately from your Web site (for example, on another disk or server), it is recommended to additionally specify the TempDirectory Uploader.TempDirectory UploadRequest.TempDirectory UploadHandler.TempDirectory property which configures a temporary folder where ASP.NET server-side part of HTML5/Flash Uploader saves files before moving them to the DestinationFolder Uploader.DestinationFolder UploadRequest.DestinationFolder UploadHandler.DestinationFolder . Thus, TempDirectory should be located at the same disk where you store files.

Filenames Conversions and Collisions

HTML5/Flash Uploader prepares files on client side in the way set by converters. Each converter specifies what to do with a file selected for upload: upload it as is or apply some transformation before upload (resize image down, extract and send icon associated with a file, or compress a file to ZIP format). Converters (except for SourceFile one) add suffixes to file names uploaded to a server. For example, the name.ext_Thumbnail0.ext filename is the result of applying Mode="*.*=Thumbnail" converter on name.ext file. For a full list of possible suffixes see the ConvertedFile.Name property description.

Filenames collisions may occur while saving uploaded files to a destination folder. If the destination folder already has a file with the same name as uploaded one, the uploaded file will be saved under its name appended by _xx, where xx is a number starting from 2. For example, if there is a file with the name name.ext in the destination folder and a user tries to upload another file with the same name then uploaded file is saved as name_02.ext file. If name_02.ext file exists as well then the recently uploaded file gets name_03.ext filename and so on.

Extended Processing of Uploaded Data

This approach requires quite a bit of code, however, this method is more flexible than autosave described before. The main idea is to handle uploaded files and data in the FileUploaded Uploader.FileUploaded UploadRequest.FileUploaded UploadHandler.FileUploaded and/or AllFilesUploaded Uploader.AllFilesUploaded UploadRequest.AllFilesUploaded UploadHandler.AllFilesUploaded event handlers of the mentioned before server-side components. The first event fires each time a user-specified file is successfully uploaded. The second event fires when the whole upload session completes and all the files, metadata, and additional data are received on the server side. It means that the first event fires as many times as number of files selected for upload, whereas the second one fires only once.

Now, when you understand the differences between these events, let us discuss how to create these event handlers. There are two steps to this process:

Creating Skeleton Event Handlers

Before creating an event handler you have to select server-side component to use. If you do not know the differences between them, please, read the server-side components section of this article.

Using Uploader and UploadRequest Controls

To add FileUploaded and/or AllFilesUploaded event handler for the ImageUploaderFlash control just specify event name in the control events list or add OnFileUploaded and/or OnAllFilesUploaded parameters declaratively. The following example creates both event handlers for the ImageUploaderFlash control.

ASP.NET
<aur:ImageUploaderFlash ID="Uploader1" runat="server"
    OnFileUploaded="FileUploaded"
    OnAllFilesUploaded="AllFilesUploaded" />

The page code-behind should contain these event handlers with the specified names:

C#
protected void FileUploaded(object sender, Aurigma.ImageUploaderFlash.FileUploadedEventArgs e)
{
    // Your code
}

protected void AllFilesUploaded(object sender, Aurigma.ImageUploaderFlash.AllFilesUploadedEventArgs e)
{
    // Your code
}

The UploadRequest event handlers can be created in the same way as analogous ImageUploaderFlash event handlers described above:

C#
<aur:UploadRequest ID="UploadRequest1" runat="server"
    OnFileUploaded="FileUploaded" 
    OnAllFilesUploaded="AllFilesUploaded" />

The same code-behind as for ImageUploaderFlash will work.

There is the example of event handler below.

Using UploadHandler Class

When using the UploadHandler you have to create a new class derived from the UploadHandler class and add events handlers to this new class. In the following example the SimpleHandler class (contained in the SimpleHandler.ashx file) is this new derived class.

C#
public class SimpleHandler : Aurigma.ImageUploaderFlash.UploadHandler
{
    public SimpleHandler()
    {
        FileUploaded += OnFileUploaded;
        AllFilesUploaded += OnAllFilesUploaded;
    }

    public void OnFileUploaded(object sender, Aurigma.ImageUploaderFlash.FileUploadedEventArgs e)
    {
        // put your code here...
    }

    public void OnAllFilesUploaded(object sender, Aurigma.ImageUploaderFlash.AllFilesUploadedEventArgs e)
    {
        // put your code here...
    }

}

Then implement these handlers, for instance, like it is shown in the example below.

And, finally, set the UploadSettings.ActionUrl property:

ASP.NET
<aur:ImageUploaderFlash runat="server">
    <UploadSettings ActionUrl="SimpleHandler.ashx" />
</aur:ImageUploaderFlash>

Writing Implementation of Event Handlers

After creating a skeleton event handler you have to write its implementation. You can accomplish any operation on the uploaded data using HTML5/Flash Uploader ASP.NET types and classes. For example, not just save all files to the same folder, but change destination depending on file type. Moreover, you can save metadata of uploaded files to your database or to an XML file which allows you to perform, for instance, various file-sorting operations. For better understanding let us separate description of the uploaded data handling into the following sections:

Files Handling

The ASP.NET server-side part of HTML5/Flash Uploader among its types has the UploadedFile class. This type holds all the data associated with a single file selected for upload (files prepared on client side by HTML5/Flash Uploader from the original file in accordance with converters set in the settings, additional fields, and other data). The FileUploaded and AllFilesUploaded events give access to the UploadedFile instances via arguments of their event handlers: FileUploadedEventArgs.UploadedFile and AllFilesUploadedEventArgs.UploadedFiles properties, respectively.

Now let us examine how to get access to uploaded files via the UploadedFile instances. Each UploadedFile object has associated collection of files prepared by HTML5/Flash Uploader converters on client side. Each of these files is represented by an instance of the ConvertedFile type. This way, the collection of converted files associated with a particular file selected for upload is accessible via the UploadedFile.ConvertedFiles property.

Each ConvertedFile has three main members to handle the file:

  • the FileStream property for getting access to the file content
  • the MoveTo(String) method for moving the file to the specified location
  • the SaveAs(String) method for copying the file to the specified location

The main difference between MoveTo(String) and SaveAs(String) methods is in the following. By the moment when the FileUploaded or AllFilesUploaded event is fired, ASP.NET server-side part of HTML5/Flash Uploader has already completed parsing of HTTP POST request(s) and saved files to a temporary folder which is configured via the TempDirectory Uploader.TempDirectory UploadRequest.TempDirectory UploadHandler.TempDirectory property. When you trigger the MoveTo(String) method, it moves the file from this temporary folder to the specified one. However, when you call the SaveAs(String) method copies the file from a temporary location to the specified folder. MoveTo(String) method works faster when you transfer the file from a temporary location (which is in the /App_Data/ folder, by default) to a location on the same disk. That is the difference. Thus, it is recommended to select temporary folder on the same disk where your file storage is located.

Metadata Handling

All the metadata uploaded along with a file is accessible through the UploadedFile properties and can be divided into the following groups:

Original File Information

This group includes properties containing information about the original file:

Converted File Information

The ConvertedFile class provides access to some additional information along with the access to the converted file. Its properties contain the following information:

  • Mode contains a converter type applied to create the converted file.
  • Size represents size (in bytes) of the converted file.
  • Height and Width represent dimensions of the created downsized image (in pixels) if the converter was set to resize an original image down.
User-defined Data

This group includes the following properties:

Event Handler Example

This example is an FileUploaded event handler implementation which saves an original file and its resized copy to the ../Gallery/ and ../Gallery/Thumbnails/ folders respectively and writes some file-related information (filenames, image dimensions, user description, and etc.) to an XML file.

C#
protected void FileUploaded(object sender, Aurigma.ImageUploaderFlash.FileUploadedEventArgs e)
{
    string galleryPath = Server.MapPath("Gallery/");
    string thumbnailsPath = galleryPath + "Thumbnails/";

    //Save original file.
    //It is the first file in ConvertedFiles collection as we set first converter mode to SourceFile.
    string sourceFileName = GetSafeFileName(galleryPath, e.UploadedFile.SourceName);
    e.UploadedFile.ConvertedFiles[0].SaveAs(System.IO.Path.Combine(galleryPath, sourceFileName));

    //Save thumbnail.
    //It is the second file in ConvertedFiles collection as we set second converter mode to Thumbnail.
    string thumbnailFileName = GetSafeFileName(thumbnailsPath, e.UploadedFile.SourceName);
    e.UploadedFile.ConvertedFiles[1].SaveAs(System.IO.Path.Combine(thumbnailsPath, thumbnailFileName));

    //Save file info.
    System.Xml.XmlDocument descriptions = new System.Xml.XmlDocument();
    if (System.IO.File.Exists(galleryPath + "Descriptions.xml"))
        descriptions.Load(galleryPath + "Descriptions.xml");
    else
        descriptions.AppendChild(descriptions.CreateElement("files"));

    System.Xml.XmlElement file = descriptions.CreateElement("file");
    file.SetAttribute("name", sourceFileName);
    file.SetAttribute("thumbName", thumbnailFileName);
    file.SetAttribute("width", Convert.ToString(e.UploadedFile.SourceWidth));
    file.SetAttribute("height", Convert.ToString(e.UploadedFile.SourceHeight));
    file.SetAttribute("description", e.UploadedFile.Description);
    descriptions.DocumentElement.AppendChild(file);
    //Save xml file with uploaded files info.
    descriptions.Save(galleryPath + "Descriptions.xml");
}

private string GetSafeFileName(string path, string fileName)
{
    // ...
}

Parsing POST Requests Using Standard ASP.NET Request Object

The last way of handling uploaded files is to parse the request manually via the intrinsic Request object of System.Web.HttpRequest class. Before the Page_Load method is called, the upload request should be converted to the standart RFC1867 format. To perform it you should add a reference to the Aurigma.ImageUploaderFlash.dll to your project and add the UploaderModule module to your web.config, like follows:

XML
<configuration>
   <!-- other sections -->
   <system.web>
        <!-- other sections -->
	<!-- IIS6 or IIS7 in Classic mode -->
        <httpModules>
            <!-- other modules -->
            <add name="UploaderModule" type="Aurigma.ImageUploaderFlash.UploaderModule"/>
        </httpModules>
        <!-- other sections -->
   </system.web>
   <!-- other sections -->
   <system.webServer>
        <!-- other sections -->
	<!-- IIS7 in Integrated mode --> 
	<!-- 	Remove <httpModules> and uncomment this section 
		if you use Integrated mode instead of Classic. 
		You can check the pipeline mode in the 
		Application Pool basic settings.

		Alternatively, you can add this param (not recommended): 
		<validation validateIntegratedModeConfiguration="false"/>

        <modules>
            <add name="UploaderModule" type="Aurigma.ImageUploaderFlash.UploaderModule"/>
        </modules>
	-->
        <!-- other sections -->
   </system.webServer>
   <!-- other sections -->
</configuration>
Note

If you choose this approach we do not recommend enabling chunks, otherwise, you will have to write significant amount of non-trivial server-side code to assembly the files on your server.

To simplify accessing the POST request fields HTML5/Flash Uploader ASP.NET provides the PostFields class. The following code sample saves original files, thumbnails, and original file-related information using described approach.

C#
private void Page_Load(System.Object sender, System.EventArgs e)
{
    if (System.String.Equals(Request.RequestType, "POST"))
    {
        string galleryPath = Server.MapPath("Gallery/");
        string thumbnailsPath = galleryPath + "Thumbnails/";

        string originalFileName = Request[string.Format(PostFields.SourceName, 0)];

        // save original file
        string sourceFileName = GetSafeFileName(galleryPath, originalFileName);
        HttpPostedFile sourceFile = Request.Files[string.Format(PostFields.File, 0, 0)];
        if (sourceFile != null)
            sourceFile.SaveAs(System.IO.Path.Combine(galleryPath, sourceFileName));
       
        // save thumbnail
        string thumbnailFileName = GetSafeFileName(thumbnailsPath, originalFileName);
        HttpPostedFile thumbnailFile = Request.Files[string.Format(PostFields.File, 1, 0)];
        if (thumbnailFile != null)
            thumbnailFile.SaveAs(System.IO.Path.Combine(thumbnailsPath, thumbnailFileName));
        
        //Save file info.
        System.Xml.XmlDocument descriptions = new System.Xml.XmlDocument();
        if (System.IO.File.Exists(galleryPath + "Descriptions.xml"))
            descriptions.Load(galleryPath + "Descriptions.xml");
        else
            descriptions.AppendChild(descriptions.CreateElement("files"));

        System.Xml.XmlElement file = descriptions.CreateElement("file");
        file.SetAttribute("name", sourceFileName);
        file.SetAttribute("thumbName", thumbnailFileName);
        file.SetAttribute("width", Request[string.Format(PostFields.SourceWidth, 0)]);
        file.SetAttribute("height", Request[string.Format(PostFields.SourceHeight, 0)]);
        file.SetAttribute("description", Request[string.Format(PostFields.Description, 0)]);
        descriptions.DocumentElement.AppendChild(file);
        //Save xml file with uploaded files info.
        descriptions.Save(galleryPath + "Descriptions.xml");
    }
}

private string GetSafeFileName(string path, string fileName)
{
    // ...
}

See Also

Reference

Manual

MSDN Articles