How to Quickly Implement BlueImp jQuery File Upload GitHub Plugin in ASP.NET Core

How to Quickly Implement BlueImp jQuery File Upload GitHub Plugin in ASP.NET Core

BlueImp jQuery File Upload Plugin is one of the top favorites of GitHub and can be downloaded from this link. In this tutorial I will implement BlueImp jQuery File Upload plugin in an ASP.NET Core Application. It will have the following features:

  • 1. Multiple file upload : Allows to select multiple files at once and upload them simultaneously.
  • 2. Drag & Drop support : Allows to upload files by dragging them from your desktop or file manager and dropping them on your browser window.
  • 3. Upload progress bar : Shows a progress bar indicating the upload progress for individual files and for all uploads combined.
  • 4. Cancelable uploads : Individual file uploads can be canceled to stop the upload progress.
  • 5. Resumable uploads : Aborted uploads can be resumed with browsers supporting the Blob API.

This jQuery File Upload will work like the demo shown below:

jQuery File Upload Demo

Let us start with the implementation.

Add Plugin CSS and JS Files to the ASP.NET Core Application

First download the plugin from GitHub in your drive, copy it’s css and js folders and paste them inside your application’s wwwroot folder. Check the below image which explains this.

css & js folders

Create the View

Here I will be creating the jQuery File Upload feature in the Home Controller and so I will be using the Index View of the Home Controller. You can use any controller as you desire.

Next in the Index.cshtml View, which is located inside the Views/Home/ folder, I copy and paste all the codes from the index.html file of the plugin. Note that you will find this index.html file in the plugin’s root folder.

Next you do the following 4 changes to the code of the View:

First Change

Change all the CSS and JS files links to map from the wwwroot folder of the application.

For Example : Change the below code line

<script src="js/demo.js"></script>

To :

<script src="~/js/demo.js"></script>

Also create a new folder called uploads inside the wwwroot folder where the files will be uploaded.

Second Change

Change @media (max-width: 767px) to @@media (max-width: 767px).

@@media (max-width: 767px) {
  #title,
  #description {
    display: none;
  }
}
Third Change

Change the name of the file upload tag from files[] to files.

You will find the file upload control having the name as files[].

<input type="file" name="files[]" multiple>
Change its name to files.
<input type="file" name="files" multiple>
Fourth Change

Add Layout = null to the View:

@{
    Layout = null;
}

The Index View full updated code is given below:

@{
    Layout = null;
}

<!DOCTYPE html>
<!--
/*
 * jQuery File Upload Demo
 * https://github.com/blueimp/jQuery-File-Upload
 *
 * Copyright 2010, Sebastian Tschan
 * https://blueimp.net
 *
 * Licensed under the MIT license:
 * https://opensource.org/licenses/MIT
 */
-->
<html lang="en">
<head>
    <!-- Force latest IE rendering engine or ChromeFrame if installed -->
    <!--[if IE]>
      <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <![endif]-->
    <meta charset="utf-8" />
    <title>jQuery File Upload Demo</title>
    <meta name="description"
          content="File Upload widget with multiple file selection, drag&drop support, progress bars, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads and client-side image resizing. Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads." />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <!-- Bootstrap styles -->
    <link rel="stylesheet"
          href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
          integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
          crossorigin="anonymous" />
    <!-- Generic page styles -->
    <style>
      #navigation {
        margin: 10px 0;
      }
      @@media (max-width: 767px) {
        #title,
        #description {
          display: none;
        }
      }
    </style>
    <!-- blueimp Gallery styles -->
    <link rel="stylesheet"
          href="https://blueimp.github.io/Gallery/css/blueimp-gallery.min.css" />
    <!-- CSS to style the file input field as button and adjust the Bootstrap progress bars -->
    <link rel="stylesheet" href="~/css/jquery.fileupload.css" />
    <link rel="stylesheet" href="~/css/jquery.fileupload-ui.css" />
    <!-- CSS adjustments for browsers with JavaScript disabled -->
    <noscript>
        <link rel="stylesheet" href="~/css/jquery.fileupload-noscript.css" />
    </noscript>
    <noscript>
        <link rel="stylesheet" href="~/css/jquery.fileupload-ui-noscript.css" />
    </noscript>
</head>
<body>
    <div class="container">
        <ul class="nav nav-tabs" id="navigation">
            <li>
                <a href="https://github.com/blueimp/jQuery-File-Upload">Project</a>
            </li>
            <li class="active">
                <a href="#">Demo</a>
            </li>
            <li>
                <a href="https://github.com/blueimp/jQuery-File-Upload/wiki">Wiki</a>
            </li>
            <li>
                <a href="https://blueimp.net">Author</a>
            </li>
        </ul>
        <h1 id="title">jQuery File Upload Demo</h1>
        <blockquote id="description">
            <p>
                File Upload widget with multiple file selection, drag&drop
                support, progress bars, validation and preview images, audio and video
                for jQuery.<br />
                Supports cross-domain, chunked and resumable file uploads and
                client-side image resizing.<br />
                Works with any server-side platform (PHP, Python, Ruby on Rails, Java,
                Node.js, Go etc.) that supports standard HTML form file uploads.
            </p>
        </blockquote>
        <!-- The file upload form used as target for the file upload widget -->
        <form id="fileupload"
              action="https://jquery-file-upload.appspot.com/"
              method="POST"
              enctype="multipart/form-data">
            <!-- Redirect browsers with JavaScript disabled to the origin page -->
            <noscript>
                <input type="hidden"
                       name="redirect"
                       value="https://blueimp.github.io/jQuery-File-Upload/" />
            </noscript>
            <!-- The fileupload-buttonbar contains buttons to add/delete files and start/cancel the upload -->
            <div class="row fileupload-buttonbar">
                <div class="col-lg-7">
                    <!-- The fileinput-button span is used to style the file input field as button -->
                    <span class="btn btn-success fileinput-button">
                        <i class="glyphicon glyphicon-plus"></i>
                        <span>Add files...</span>
                        <input type="file" name="files" multiple />
                    </span>
                    <button type="submit" class="btn btn-primary start">
                        <i class="glyphicon glyphicon-upload"></i>
                        <span>Start upload</span>
                    </button>
                    <button type="reset" class="btn btn-warning cancel">
                        <i class="glyphicon glyphicon-ban-circle"></i>
                        <span>Cancel upload</span>
                    </button>
                    <button type="button" class="btn btn-danger delete">
                        <i class="glyphicon glyphicon-trash"></i>
                        <span>Delete selected</span>
                    </button>
                    <input type="checkbox" class="toggle" />
                    <!-- The global file processing state -->
                    <span class="fileupload-process"></span>
                </div>
                <!-- The global progress state -->
                <div class="col-lg-5 fileupload-progress fade">
                    <!-- The global progress bar -->
                    <div class="progress progress-striped active"
                         role="progressbar"
                         aria-valuemin="0"
                         aria-valuemax="100">
                        <div class="progress-bar progress-bar-success"
                             style="width: 0%;"></div>
                    </div>
                    <!-- The extended global progress state -->
                    <div class="progress-extended"> </div>
                </div>
            </div>
            <!-- The table listing the files available for upload/download -->
            <table role="presentation" class="table table-striped">
                <tbody class="files"></tbody>
            </table>
        </form>
        <div class="panel panel-default">
            <div class="panel-heading">
                <h3 class="panel-title">Demo Notes</h3>
            </div>
            <div class="panel-body">
                <ul>
                    <li>
                        The maximum file size for uploads in this demo is
                        <strong>999 KB</strong> (default file size is unlimited).
                    </li>
                    <li>
                        Only image files (<strong>JPG, GIF, PNG</strong>) are allowed in
                        this demo (by default there is no file type restriction).
                    </li>
                    <li>
                        Uploaded files will be deleted automatically after
                        <strong>5 minutes or less</strong> (demo files are stored in
                        memory).
                    </li>
                    <li>
                        You can <strong>drag & drop</strong> files from your desktop
                        on this webpage (see
                        <a href="https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support">Browser support</a>).
                    </li>
                    <li>
                        Please refer to the
                        <a href="https://github.com/blueimp/jQuery-File-Upload">project website</a>
                        and
                        <a href="https://github.com/blueimp/jQuery-File-Upload/wiki">documentation</a>
                        for more information.
                    </li>
                    <li>
                        Built with the
                        <a href="https://getbootstrap.com/">Bootstrap</a> CSS framework
                        and Icons from <a href="https://glyphicons.com/">Glyphicons</a>.
                    </li>
                </ul>
            </div>
        </div>
    </div>
    <!-- The blueimp Gallery widget -->
    <div id="blueimp-gallery"
         class="blueimp-gallery blueimp-gallery-controls"
         aria-label="image gallery"
         aria-modal="true"
         role="dialog"
         data-filter=":even">
        <div class="slides" aria-live="polite"></div>
        <h3 class="title"></h3>
        <a class="prev"
           aria-controls="blueimp-gallery"
           aria-label="previous slide"
           aria-keyshortcuts="ArrowLeft"></a>
        <a class="next"
           aria-controls="blueimp-gallery"
           aria-label="next slide"
           aria-keyshortcuts="ArrowRight"></a>
        <a class="close"
           aria-controls="blueimp-gallery"
           aria-label="close"
           aria-keyshortcuts="Escape"></a>
        <a class="play-pause"
           aria-controls="blueimp-gallery"
           aria-label="play slideshow"
           aria-keyshortcuts="Space"
           aria-pressed="false"
           role="button"></a>
        <ol class="indicator"></ol>
    </div>
    <!-- The template to display files available for upload -->
    <script id="template-upload" type="text/x-tmpl">
        {% for (var i=0, file; file=o.files[i]; i++) { %}
        <tr class="template-upload fade{%=o.options.loadImageFileTypes.test(file.type)?' image':''%}">
            <td>
                <span class="preview"></span>
            </td>
            <td>
                <p class="name">{%=file.name%}</p>
                <strong class="error text-danger"></strong>
            </td>
            <td>
                <p class="size">Processing...</p>
                <div class="progress progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"><div class="progress-bar progress-bar-success" style="width:0%;"></div></div>
            </td>
            <td>
                {% if (!o.options.autoUpload && o.options.edit && o.options.loadImageFileTypes.test(file.type)) { %}
                <button class="btn btn-success edit" data-index="{%=i%}" disabled>
                    <i class="glyphicon glyphicon-edit"></i>
                    <span>Edit</span>
                </button>
                {% } %}
                {% if (!i && !o.options.autoUpload) { %}
                <button class="btn btn-primary start" disabled>
                    <i class="glyphicon glyphicon-upload"></i>
                    <span>Start</span>
                </button>
                {% } %}
                {% if (!i) { %}
                <button class="btn btn-warning cancel">
                    <i class="glyphicon glyphicon-ban-circle"></i>
                    <span>Cancel</span>
                </button>
                {% } %}
            </td>
        </tr>
        {% } %}
    </script>
    <!-- The template to display files available for download -->
    <script id="template-download" type="text/x-tmpl">
        {% for (var i=0, file; file=o.files[i]; i++) { %}
        <tr class="template-download fade{%=file.thumbnailUrl?' image':''%}">
            <td>
                <span class="preview">
                    {% if (file.thumbnailUrl) { %}
                    <a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" data-gallery><img src="{%=file.thumbnailUrl%}"></a>
                    {% } %}
                </span>
            </td>
            <td>
                <p class="name">
                    {% if (file.url) { %}
                    <a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" {%=file.thumbnailUrl?'data-gallery':''%}>{%=file.name%}</a>
                    {% } else { %}
                    <span>{%=file.name%}</span>
                    {% } %}
                </p>
                {% if (file.error) { %}
                <div><span class="label label-danger">Error</span> {%=file.error%}</div>
                {% } %}
            </td>
            <td>
                <span class="size">{%=o.formatFileSize(file.size)%}</span>
            </td>
            <td>
                {% if (file.deleteUrl) { %}
                <button class="btn btn-danger delete" data-type="{%=file.deleteType%}" data-url="{%=file.deleteUrl%}" {% if (file.deleteWithCredentials) { %} data-xhr-fields='{"withCredentials":true}' {% } %}>
                    <i class="glyphicon glyphicon-trash"></i>
                    <span>Delete</span>
                </button>
                <input type="checkbox" name="delete" value="1" class="toggle">
                {% } else { %}
                <button class="btn btn-warning cancel">
                    <i class="glyphicon glyphicon-ban-circle"></i>
                    <span>Cancel</span>
                </button>
                {% } %}
            </td>
        </tr>
        {% } %}
    </script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"
            integrity="sha384-nvAa0+6Qg9clwYCGGPpDQLVpLNn0fRaROjHqs13t4Ggj3Ez50XnGQqc/r8MhnRDZ"
            crossorigin="anonymous"></script>
    <!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included -->
    <script src="~/js/vendor/jquery.ui.widget.js"></script>
    <!-- The Templates plugin is included to render the upload/download listings -->
    <script src="https://blueimp.github.io/JavaScript-Templates/js/tmpl.min.js"></script>
    <!-- The Load Image plugin is included for the preview images and image resizing functionality -->
    <script src="https://blueimp.github.io/JavaScript-Load-Image/js/load-image.all.min.js"></script>
    <!-- The Canvas to Blob plugin is included for image resizing functionality -->
    <script src="https://blueimp.github.io/JavaScript-Canvas-to-Blob/js/canvas-to-blob.min.js"></script>
    <!-- blueimp Gallery script -->
    <script src="https://blueimp.github.io/Gallery/js/jquery.blueimp-gallery.min.js"></script>
    <!-- The Iframe Transport is required for browsers without support for XHR file uploads -->
    <script src="~/js/jquery.iframe-transport.js"></script>
    <!-- The basic File Upload plugin -->
    <script src="~/js/jquery.fileupload.js"></script>
    <!-- The File Upload processing plugin -->
    <script src="~/js/jquery.fileupload-process.js"></script>
    <!-- The File Upload image preview & resize plugin -->
    <script src="~/js/jquery.fileupload-image.js"></script>
    <!-- The File Upload audio preview plugin -->
    <script src="~/js/jquery.fileupload-audio.js"></script>
    <!-- The File Upload video preview plugin -->
    <script src="~/js/jquery.fileupload-video.js"></script>
    <!-- The File Upload validation plugin -->
    <script src="~/js/jquery.fileupload-validate.js"></script>
    <!-- The File Upload user interface plugin -->
    <script src="~/js/jquery.fileupload-ui.js"></script>
    <!-- The main application script -->
    <script src="~/js/demo.js"></script>
    <!-- The XDomainRequest Transport is included for cross-domain file deletion for IE 8 and IE 9 -->
    <!--[if (gte IE 8)&(lt IE 10)]>
      <script src="~/js/cors/jquery.xdr-transport.js"></script>
    <![endif]-->
</body>
</html>

Create the Models Classes

Create 2 Model classes inside the Models folder of your app. These files are:

1. UploadFilesResult.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace jFileUpload.Models
{
    public class UploadFilesResult
    {
        public string name { get; set; }
        public long size { get; set; }
        public string type { get; set; }
        public string url { get; set; }
        public string deleteUrl { get; set; }
        public string thumbnailUrl { get; set; }
        public string deleteType { get; set; }
    }
}

2. JsonFiles.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace jFileUpload.Models
{
    public class JsonFiles
    {
        public UploadFilesResult[] files;
        public string TempFolder { get; set; }
        public JsonFiles(List<UploadFilesResult> filesList)
        {
            files = new UploadFilesResult[filesList.Count];
            for (int i = 0; i < filesList.Count; i++)
            {
                files[i] = filesList.ElementAt(i);
            }
        }
    }
}

These 2 classes stores the information of the uploaded files.

Create the Controller

In your Home Controller add the dependency to IWebHostEnvironment class so that the Controller can get the hosting knowledge from Dependency Injection feature of ASP.NET Core.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using jFileUpload.Models;

namespace jFileUpload.Controllers
{
    public class HomeController : Controller
    {
        private IWebHostEnvironment hostingEnvironment;
        public HomeController(IWebHostEnvironment environment)
        {
            hostingEnvironment = environment;
        }

        public IActionResult Index()
        {
            return View();
        }
    }
}

Next, add Upload and Delete actions to the Controller:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using jFileUpload.Models;

namespace jFileUpload.Controllers
{
    public class HomeController : Controller
    {
        private IWebHostEnvironment hostingEnvironment;
        public HomeController(IWebHostEnvironment environment)
        {
            hostingEnvironment = environment;
        }

        public IActionResult Index()
        {
            return View();
        }

        [HttpPost]
        public async Task<JsonResult> Upload(IFormFile files)
        {
            var resultList = new List<UploadFilesResult>();

            string path = Path.Combine(hostingEnvironment.WebRootPath, "uploads/" + files.FileName);
            using (var stream = new FileStream(path, FileMode.Create))
            {
                await files.CopyToAsync(stream);
            }

            UploadFilesResult uploadFiles = new UploadFilesResult();
            uploadFiles.name = files.FileName;
            uploadFiles.size = files.Length;
            uploadFiles.type = "image/jpeg";
            uploadFiles.url = "/uploads/" + files.FileName;
            uploadFiles.deleteUrl = "/Home/Delete?file=" + files.FileName;
            uploadFiles.thumbnailUrl = "/uploads/" + files.FileName;
            uploadFiles.deleteType = "GET";

            resultList.Add(uploadFiles);
            return Json(new { files = resultList });
        }

        public JsonResult Delete(string file)
        {
            System.IO.File.Delete(Path.Combine(hostingEnvironment.WebRootPath, "uploads/" + file));
            return Json("OK");
        }
    }
}

Explanation : The Upload action is called when the plugin uploads the files. This action has a parameter – IFormFile files, which gets the uploaded files from the view by the technique called Model Binding.

I save these files inside the uploads folders and this folder is inside the wwwroot folder of the application. The below code lines does this part.

string path = Path.Combine(hostingEnvironment.WebRootPath, "uploads/" + files.FileName);
using (var stream = new FileStream(path, FileMode.Create))
{
    await files.CopyToAsync(stream);
}

I used 2 classes to store the information of all the uploaded files. These classes are:

  • 1. UploadFilesResult
  • 2. JsonFiles

In the end I return the object of JsonFiles, which contains the uploaded files information, to the view. This information is returned in JSON format.

An important code line is the setting of deleteUrl of the UploadFilesResult class:

uploadFiles.deleteUrl = "/Home/Delete?file=" + file.FileName;

I specifically assigned the value of – "/Home/Delete?file=" + file.FileName, so that the Delete Action method is called when the delete button is clicked in the View.

The Delete action method takes the file name in it’s parameter and simply deletes the file from it’s stored location.

The stored location of the files are wwwroot/uploads.

Once the file is deleted it return OK response in JSON to the View:

System.IO.File.Delete(Path.Combine(hostingEnvironment.WebRootPath, "uploads/" + file));
return Json("OK");

Change the URL in the “demo.js” script

Open the demo.js kept inside the wwwroot/js folder. In this file comment out the code line that says – url: 'server/php/' and add url: 'Home/Upload'. This is done so that the Upload action method is called when the upload button is clicked.

// Initialize the jQuery File Upload widget:
$('#fileupload').fileupload({
  // Uncomment the following to send cross-domain cookies:
  //xhrFields: {withCredentials: true},
  //url: 'server/php/'
  url: 'Home/Upload'  // This will target Home Controller's upload action
});

You can download the source code using the below link:

Download

Conclusion

I hope you like this tutorial on jQuery File Upload. Download the source codes and use it freely in your projects. Don’t forget to check out my other tutorials on ASP.NET Core.

SHARE THIS ARTICLE

  • linkedin
  • reddit
yogihosting

ABOUT THE AUTHOR

I hope you enjoyed reading this tutorial. If it helped you then consider buying a cup of coffee for me. This will help me in writing more such good tutorials for the readers. Thank you. Buy Me A Coffee donate

Comments

  1. Juan Ibaz says:

    Hello,
    I would like to put my file row and the progress bar below it. I have tried different ways but I haven’t get any result.
    Is is a way to do it?

    1. yogihosting says:

      Everything is possible, you can do that by moving the relevant html elements from their current position to a new div element. Check the html structure using the Chrome Developer Tools to find out these element. Thank you.

Leave a Reply

Your email address will not be published. Required fields are marked *