Ajax Multi File Upload in ASP.NET MVC 5

Date Posted: January 9, 2017, 4:37 pm


In this tutorial you will learn how to create a multi-file upload form that submits via Ajax. The plan is to store the files in a folder located in your server and save the file names in single database field named “images” with the format of a JSON string, like this: [“image_101.jpg”,”image_102.jpg”,”image_103.jpg”,”image_104.jpg”,”image_105.jpg”, …. ] but if you do not like this format you can still use this tutorial, you just need to do a few changes in the controller to fit your web app requirements.

Let’s get started.

1. Include the CDN script bellow into the footer part of your application (after jquery). This is the plugin that we’ll be using for submitting files asynchronously via Ajax.

1
@Scripts.Render("//cdnjs.cloudflare.com/ajax/libs/jquery.form/3.51/jquery.form.min.js")

2. In your razor view, add the following form:

1
2
3
4
5
6
7
8
9
10
11
12
@using (Html.BeginForm("Index", "Upload", new { id = @Model.id }, FormMethod.Post, new { @class = "upload-images" }))
{
    @Html.AntiForgeryToken()
    @Html.HiddenFor(model => model.id)
       
    <div class="form-group">
        @Html.LabelFor(model => model.images, "Select Images")
        <input type="file" name="images[]" accept="image/*" class="form-control" multiple />
    </div>
       
    <input type="submit" class="btn btn-success" value="Upload" />
}

3. Then in your controller, include the the method bellow.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
[HttpPost]
[ValidateAntiForgeryToken]
public string Index([Bind(Include = "images")] Product product)
{
    /* Let's put our variables in a dictionary */
    var response = new Dictionary<string, string> {
        { "status", "0" },
        { "message", "" },
        { "images", "" }
    };

    if (ModelState.IsValid)
    {
        /* Image uploade handler */
        try
        {
            HttpFileCollection hfc = System.Web.HttpContext.Current.Request.Files; /* Retrieve files from form request */
            string path = "/Content/Images/Uploads/"; /* Location to store images */
            List<string> images = new List<string>(); /* Initialize an empty list for our images */

            /* Check if Products Directory exists */
            if (!Directory.Exists(path))
            {
                /* Create Products directory if not exists */
                Directory.CreateDirectory(Server.MapPath("~") + path);
            }

            /* Process each image */
            for (int i = 0; i < hfc.Count; i++)
            {
                HttpPostedFile hpf = hfc[i];
                if (hpf.ContentLength > 0)
                {
                    string file_name_original = Path.GetFileNameWithoutExtension(hpf.FileName); /* Original file name with extension */
                    string file_name = GlobalMethods.GenerateRandomString(20); /* Generate a random string for our image name */
                    string file_extension = Path.GetExtension(hpf.FileName); /* Get file extension */
                    string file_path_with_file_name = path + file_name + file_extension; /* Final image path */

                    /* Append single image to our images list */
                    images.Add(file_name + file_extension);

                    /* Move files to the specified directory on the "path" variable */
                    hpf.SaveAs(Server.MapPath(file_path_with_file_name));
                }
            }

            /* If there is an image uploaded, let's include them to the response dictionary */
            if (images.Count > 0)
            {
                if (!String.IsNullOrEmpty(original_data_detached.images))
                {
                    /* Get existing images from database then convert it to an array */
                    var old_images_array = new JavaScriptSerializer().Deserialize<dynamic>(original_data_detached.images);

                    /* Add old images to the new images list variable*/
                    foreach (var image in old_images_array)
                    {
                        images.Add(image);
                    }
                }

                /* Convert images list to json */
                response["images"] = new JavaScriptSerializer().Serialize(images);

                product.images = response["images"];
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
       
        db.Entry(product).State = EntityState.Modified;

        /* Do not update images field if there are no new posted images */
        if (String.IsNullOrEmpty(product.images))
        {
            db.DontUpdateProperty<Product>("images");
        }

        db.SaveChanges();
        response["status"] = "1";
        response["message"] = "Successfully Updated";
    }

    /* Then we return the Dictionary in json format to our front-end */
    string json = new JavaScriptSerializer().Serialize(response);
    return json;
}

Note: You will have to change the model names above to fit in your application. But if you want to see my model implementation, here it is:

1
2
3
4
5
6
7
8
9
10
11
12
13
namespace MyApp.Models
{
    public class Product
    {
        public int id { get; set; }
        public string images { get; set; }
    }

    public class ProductDBContext : DbContext
    {
        public DbSet<Product> Products { get; set; }
    }
}

4. Create the file: ./Scripts/app.js then add the code bellow. This will handle our ajax submit. Make sure to include this file in the footer part of your application (AFTER jquery and jquery.form)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$(document).ready(function () {
    $('.upload-images').ajaxForm({
        success: function (response, textStatus, xhr, form) {
            response = JSON.parse(response);
                                         
            if (response.status == 1) {
                    alert(response.message);
                }
            }
            if (response.images) {
                $.each(JSON.parse(response.images), function (index, image) {
                    /* Code what to do with the returned images */
                });
            }
        }
    });
});

5. That’s it. now test your web app.

About author


Carl Victor Fontanos

A fine gentleman specializing in front-end and back-end development with extensive experience building high performance web applications that keeps users engaged and help businesses grow.

 
Hire Me