Form designer: How to add multiple file attachments using a single AJAX file upload control


#1

This article shows you how to upload multiple attachments using the AjaxFileUpload of the AJAX Control Toolkit from DevExpress.
It also has the functionality to Drag & Drop to upload the files.

Note: The sample process and example code are provided as is and are implemented based on this component. You can adapt the code if you desire to integrate with another control. You might need to get the proper license if you would like to use the AJAX Control Toolkit in production. Please contact DevExpress for this matter.

Preconditions:

1- You must install the AJAX Control Toolkit on the web application server:

2- Copy the file AjaxControlToolkit.dll located in C:\Users\[yourUser]\Documents\ASP.NET AJAX Control Toolkit\Bin\ to the \wfgen\wfapps\webforms\bin folder

NOTE: In Visual Studio, you can also use NuGet Console Manager to install the kit and get the AjaxControlToolkit.dll file.

3- If non-existant, create a web.config file in the folder \wfgen\wfapps\webforms\ and add the following configurations:

<?xml version="1.0"?>
<configuration>
  <system.webServer>
    <handlers>
      <add name="AjaxFileUploadHandler" verb="*"
        path="AjaxFileUploadHandler.axd"
        type="AjaxControlToolkit.AjaxFileUploadHandler, 
          AjaxControlToolkit"/>
    </handlers>
  </system.webServer>
</configuration>

Installation

1- Copy the AjaxFileUpload.txt file to \wfgen\App_Data\Templates\Forms\[language]\Custom\fields

2-In the form designer, create the file process data(s) with name FILE1, FILE2, …, FILEN (as much as you need). Note: the code-behind is referencing to FILE1, FILE2, etc. That is why you have to name it this way.

3- In the form designer, add the AjaxFileUpload tool (Tools dropdown / under Custom) to one of the form section.

4- In the form designer code-behind, copy-paste the code below:

protected void Page_Load(object sender, EventArgs e)
{
     base.Page_Load(sender, e);
	    
     if (!Page.IsPostBack)
     {
         // ** Save the storagepath in cookie for later access by AjaxFileUpload_UploadComplete()
         Response.Cookies.Add(new HttpCookie("storagepath", this.StoragePath));
     }

     // ** Add our custom file attachments management function on form submit
     submitButton.Click += new EventHandler(SubmitButton_Click_HandleFileUpload);
}
	
/// <summary>
/// UploadComplete event called by the AjaxFileUpload control for each file upload
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void AjaxFileUpload_UploadComplete(object sender, AjaxControlToolkit.AjaxFileUploadEventArgs e)
{
     string storagePath = Request.Cookies["storagepath"].Value;
     string fileUploadsPath = storagePath + @"\fileUploads\";

     if (!System.IO.Directory.Exists(fileUploadsPath))
     {
         System.IO.Directory.CreateDirectory(fileUploadsPath);
     }

     string filePath = fileUploadsPath + e.FileName;

     AjaxControlToolkit.AjaxFileUpload fu = sender as AjaxControlToolkit.AjaxFileUpload;

     // ** Save the file in the action instance folder e.g. 
     // e.g. \wfgen\App_Data\Files\EFormAspx\2018\03\13\92\1\1da5ab5d-c8f0-496a-90e4-ab87f60fda74\fileUploads
     fu.SaveAs(filePath);
}

/// <summary>
/// File attachments management function on form submit
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void SubmitButton_Click_HandleFileUpload(object sender, EventArgs e)
{
     string fileUploadsPath = this.StoragePath + @"\fileUploads\";

     if (System.IO.Directory.Exists(fileUploadsPath))
     {
         System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(fileUploadsPath);

         int i = 0;

         // For each file attachments found in \fileUploads, update the FILE1..N in form data
         foreach (System.IO.FileInfo fi in di.GetFiles())
         {
             i++;

             // Create the FILE1..N column if missing in formdata
             if (!this.FormData.Tables[0].Columns.Contains("FILE" + i))
             {
                 this.FormData.Tables[0].Columns.Add(new System.Data.DataColumn("FILE" + i, Type.GetType("System.String")));
             }

             // Set the file attachment path (format: fileuploads\myfile.txt) to the corresponding FORM1..N in formdata
             this.FormData.Tables[0].Rows[0]["FILE" + i] = @"fileUploads\" + fi.Name;
         }

         // Save the updated formdata
         SaveFormData(this.FormData);
     }
}

5- In the desired action, add the OUT parameters mapping
e.g. FILE1 : OUT : FILE1, FILE2 : OUT : FILE2, …, FILEN : OUT : FILEN

You should have something like this after adding all FILEN parameters

Here is a sample process that implements this functionality:

https://advantys.box.com/v/AjaxFileUploadExample

Documentation of the AjaxFileUpload Control (Properties, Methods, Events and more):

https://github.com/DevExpress/AjaxControlToolkit/wiki/AjaxFileUpload