Saving Uploaded Files in ActiveX/Java Uploader ASP.NET

As you know ActiveX/Java 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 ActiveX/Java 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 ActiveX/Java 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 ActiveX/Java 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 ActiveX/Java Uploader ASP.NET components.

Server-side Components

All the ActiveX/Java Uploader ASP.NET classes and types are located in the Aurigma.ImageUploader.dll assembly. There are three main ones allowing to process the data uploaded from client computers (Uploader, 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:

  • Uploader is a WebForms control. This control can both embed ActiveX/Java Uploader in a web page (e.g. using Microsoft Visual Studio designer) and handle the data being uploaded by ActiveX/Java Uploader from client computers at run-time. Use this component if you host ActiveX/Java Uploader and receive uploads at the same web page. For more information on how to embed ActiveX/Java Uploader in a web page see the Quick Start with ActiveX/Java Uploader ASP.NET topic.
  • UploadRequest is a non-visual WebForms control. It is a right choice if you set up ActiveX/Java 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 ActiveX/Java Uploader and will expose API to access the files and data.

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, ActiveX/Java Uploader will try to create it.

Also autosave supports the Uploader.FolderProcessingMode feature that allows uploading whole folders rather than just files and restoring their structure on server side automatically, see the Uploading Folders in ActiveX/Java Uploader ASP.NET topic for more information.

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 Uploader control in your page as it is described in the Quick Start with ActiveX/Java Uploader ASP.NET topic, configure the control like it is shown below:

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

Autosave via UploadRequest Control

This control is configured in the same manner as Uploader. Additionally you have to configure the UploadSettings.ActionUrl property, set it to a URL to a page where the UploadRequest control is hosted (both absolute and relative URLs are supported), as it is shown here:

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

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.ImageUploader.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 ActiveX/Java 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

ActiveX/Java Uploader prepares files on client side in the way set by so-called 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 Uploader 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 Uploader control.

ASP.NET
<aur:Uploader 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.ImageUploader.FileUploadedEventArgs e)
{
    // Your code
}

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

The UploadRequest event handlers can be created in the same way as analogous Uploader event handlers described above. There is the only difference - in case of using UploadRequest you have to set the UploadSettings.ActionUrl property to the page containing the UploadRequest instance.

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.ImageUploader.UploadHandler
{
    public SimpleHandler()
    {
        FileUploaded += OnFileUploaded;
        AllFilesUploaded += OnAllFilesUploaded;
    }

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

    public void OnAllFilesUploaded(object sender, Aurigma.ImageUploader.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:Uploader runat="server">
    <UploadSettings ActionUrl="SimpleHandler.ashx" />
</aur:Uploader>

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 ActiveX/Java 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 ActiveX/Java 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 ActiveX/Java 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 ActiveX/Java 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 ActiveX/Java 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:

File Location

There is only one property in this group - UploadedFile.RelativePath which returns a relative path to the original file on the client machine. This property makes sense only if ActiveX/Java Uploader is allowed to upload folders (FolderProcessingMode has Upload value).

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.ImageUploader.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, ASP.NET initializes the Request object, i.e. finishes receiving HTTP POST request from a client computer and fills the Form and Files collections in. To simplify accessing the POST request fields ActiveX/Java Uploader ASP.NET provides the PostFields class.

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.

Note

ActiveX/Java Uploader sends a HEAD request before the POST one to check if authentication is needed. So, you should check the type of Request and handle POST requests only.

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/";

        int fileCount = int.Parse(Request[PostFields.PackageFileCount]);
        for (int i = 0; i < fileCount; i++)
        {
            string originalFileName = Request[string.Format(PostFields.SourceName, i)];

            // save original file
            string sourceFileName = GetSafeFileName(galleryPath, originalFileName);
            HttpPostedFile sourceFile = Request.Files[string.Format(PostFields.File, 0, i)];
            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, i)];
            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, i)]);
            file.SetAttribute("height", Request[string.Format(PostFields.SourceHeight, i)]);
            file.SetAttribute("description", Request[string.Format(PostFields.Description, i)]);
            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