« Back
in MVC dropzonejs C# read.

Easy File Uploads in MVC with DropzoneJs.

File uploading is one of those things that's pretty standard for websites. Getting it right and customizable to your needs usually requires a little more work though. Especially if the business requirement is restricting file types or wants some custom events to happen based on event x, and having backward compatibility or a fancy drag and drop area.

DropzoneJs does a lot of the plumbing and has all the above features mentioned and it's open source!

Just to note though, the only thing it doesn't do so far is read the first few bytes of a file to double check its contents. It does check mime-type and extensions though which is a plus. So that part you would have to implement yourself.

Key Features

Some key features I like about dropzone are:

  • Can limit maximum number of files
  • Can limit file sizes
  • Has thumbnails
  • Can restrict file types
  • Has old browser fallback options
  • Fires all sorts of events

DropzoneJs and MVC

So let's get something up to see what we can do. SirKirby was already nice enough to create a nuget package for us so let's install that in a new MVC application project.
Install-Package dropzone

In the BundleConfig.cs add the dropzone bundle:

bundles.Add(new ScriptBundle("~/bundles/dropzone").Include(  
                     "~/Scripts/dropzone/dropzone.js"));

Then add that to your _Layout.cshtml if you're using the default shared layout.

A Little Business Requirement

Before we move onto the next part, I'd like to take a step back and consider a business requirement for the upload that you may have in the real world. In our mvc view, we don't want to be able to just let the user upload anything. It might be a requirement that getting to the view in the first place means the user might only be allowed a maximum of 1 file upload and their acccount only allows them a 2MB limit, and they can only upload images. So how do we impose these restrictions dynamically for each user?

Let's say we've already fetched the user from our data store of choice. Now let's build a view model for our view:

    public class UploadViewModel
    {
        public string UserEmail { get; set; }
        public int FileSizeLimitMB { get; set; }
        public int MaxFiles { get; set; }
        public string ContentTypes { get; set; }
    }

Okay cool. So when we go to the actual view we get something like this:

@model FileUploader.Models.UploadViewModel

<div class="jumbotron">  
    @using (Html.BeginForm("Upload", "FrameUpload", FormMethod.Post, new { id = "dropzoneForm", @class="dropzone", enctype="multipart/form-data" }))
    {
        <div class="fallback">
            <input name="file" type="file" multiple />
            <input type="submit" value="Upload" />
        </div>
        @Html.HiddenFor(m=>m.UserEmail)
    }
</div>

<script type="text/javascript">  
    $(function () { //JQuery's document.ready

        Dropzone.options.dropzoneForm = {
            init: function () {
                this.on("complete", function (data) {
                    //do something on complete event
                });
            },
            maxFilesize:parseInt(@Model.FileSizeLimitMB),
            maxFiles:parseInt(@Model.MaxFiles),
            acceptedFiles: "@Model.ContentTypes"
        };
    });
</script>  

We've piped into the javascript variables that we got from our UploadViewModel. acceptedFiles would be a comma separated string of accepted extensions or content types. In this case it would be "image/*" but it could have easily been something like ".doc,.docx,.pdf,.txt,.xls,.xlsx" and so forth if the user was only allowed document types. This way, we only write this view once but it's dynamic enough based on our business requirements.

Saving The Files

public void Upload(UploadViewModel model)  
{
    string fName = "";
    foreach (string fileName in Request.Files)
    {
        HttpPostedFileBase file = Request.Files[fileName];
        fName = file.FileName;
        if (file != null && file.ContentLength > 0)
        {
            string path = Server.MapPath(String.Format("~/Uploads/{0}/", model.UserEmail));

            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }

            file.SaveAs(path + fName);       
        }
    }   
}

Here, we decided to create a folder structure of Uploads/{UserEmail} and stored all the user's files there. That's all there is to it.

Thanks for reading.

comments powered by Disqus