Click here to Skip to main content
15,879,326 members
Articles / Web Development / ASP.NET
Tip/Trick

ResumableJS with ASP.NET MVC

Rate me:
Please Sign up or sign in to vote.
4.20/5 (4 votes)
17 Dec 2012CPOL 20.2K   645   7   5
Asp.net implementation for the resumable.js

Introduction

I searched a lot for a resumable, chunks based uploader, and finally I found this one: https://github.com/23/resumable.js but the problem was that there is no source code available in ASP.NET. So I decided to implement my own code in order to use it. 

Background 

This uploader method is very safe and fast, because it uses a chunks method (needs html5 in javascript's side), and it upload chunks in parallel.

Using the code

The uploader uses three main Actions (get, post, options):  

The Get method will check if the chunk exists, and you can disable it in javascript by setting the option "Test" to false. 

C#
[HttpGet]
public void UploadFile()
{
    var queryString = Request.QueryString;
    if (queryString.Count == 0) return;

    try
    {
        // Read parameters
        var uploadToken = queryString.Get("upload_Token");
        int resumableChunkNumber = int.Parse(queryString.Get("resumableChunkNumber"));
        //var resumableIdentifier = queryString.Get("resumableIdentifier");
        //var resumableChunkSize = queryString.Get("resumableChunkSize");
        //var resumableTotalSize = queryString.Get("resumableTotalSize");
        var resumableFilename = queryString.Get("resumableFilename");
    

        // Check for existance
        var filePath = string.Format("{0}/{1}/{1}.part{2}", TEMP_URL, 
             uploadToken, resumableChunkNumber.ToString("0000"));
        var localFilePath = Server.MapPath(filePath);
        bool fileExists = System.IO.File.Exists(localFilePath);

        // Create Response
        if (fileExists)
        {
            Response.Status = "200 OK";
            Response.StatusCode = 200;
        }
        else
        {
            Response.Status = "404 Not Found";
            Response.StatusCode = 404;
        }
    }
    catch (Exception exception)
    {
        Logger.Error(this, "Failed to process uploading Get request.", exception);
    }
}  

The options method is used in some browsers (Chrome, Firefox):

C#
[HttpOptions]
[ActionName("UploadFile")]
public void UploadFileOptions()
{
    Response.StatusCode = (int)HttpStatusCode.OK;
}

The post method will save the chunks on the disk: 

C#
[HttpPost]
[ActionName("UploadFile")]
public async void UploadFilePost()
{
    var queryString = Request.Form;
    if (queryString.Count == 0) return;

    try
    {
        // Read parameters
        var uploadToken = queryString.Get("upload_Token");
        int resumableChunkNumber = int.Parse(queryString.Get("resumableChunkNumber"));
        var resumableFilename = queryString.Get("resumableFilename");
       
        // Save File
        if (Request.Files.Count == 0)
        {
            Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError;
            Logger.Warn("", "Request sent whithout any files !!");
        }
        else
        {
            var filePath = string.Format("{0}/{1}/{1}.part{2}", 
                 TEMP_URL, uploadToken, resumableChunkNumber.ToString("0000"));
            var localFilePath = Server.MapPath(filePath);
            
            if (!System.IO.File.Exists(localFilePath))
            {
                Request.Files[0].SaveAs(localFilePath);
            }

        }
    }
    catch (Exception exception)
    {
        return null;
    }
} 

Finally the Commit Action, which will merge the chunks into one file: 

C#
[HttpPost]
public JsonResult CommitUpload()
{
    var results = new FileUploadResult();

    try
    {
        var queryString = Request.Form;
        if (queryString.Count == 0) return null;

        // Read parameters
        var uploadToken = queryString.Get("upload_Token");
        var resumableFilename = queryString.Get("resumableFilename");
        int resumableChunkSize = int.Parse(queryString.Get("resumableChunkSize"));
        long resumableTotalSize = long.Parse(queryString.Get("resumableTotalSize"));
       
        string fileUrl = String.Empty;

        var filePath = string.Format("{0}/{1}/", TEMP_URL, uploadToken);
        var directory = WebDirectory.MapPath(filePath);

        lock (_lock)
        {
            if (Directory.Exists(directory))
            {
                var files = Directory.GetFiles(directory);
                if (GetTotalSize(files) == resumableTotalSize)
                {
                    var fileRelativePath = this.SaveUploadedFile(files, resumableFilename);
                    if (!string.IsNullOrEmpty(fileRelativePath))
                    {
                        fileUrl = fileRelativePath.Replace("~/", Site.MediaServerUrl);
                        Directory.Delete(directory);
                    }
                }
            }
        }

        // Generate Result
        results = new FileUploadResult(resumableFilename, fileUrl, true, 
          string.Format(Resources.Global.FileUploadSuccess, resumableFilename));

        Response.Charset = System.Text.Encoding.UTF8.WebName;
        Response.ContentType = "text/html;charset=utf-8";

    }
    catch (Exception exception)
    {
        return null;
    }
 
    return Json(results);
}

And this is the Result Model:

C#
[DataContract]
public class FileUploadResult
{
    [DataMember]
    public string FileName { get; set; }
    [DataMember]
    public string FileUrl { get; set; }
    [DataMember]
    public bool Succeed { get; set; }
    [DataMember]
    public string Message { get; set; }

    public FileUploadResult()
    {
    }

    public FileUploadResult(string fileName, string fileUrl, bool succeed, string message)
    {
        FileName = fileName;
        FileUrl = fileUrl;
        Succeed = succeed;
        Message = message;
    }
}  

You will find the JavaScript use method in the original site.  

Notes 

I modified something in the original JavaScript code, so you cannot use the original file with my implementation. 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Technical Lead
Lebanon Lebanon
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionWhat does UploadFileOptions method do? Pin
Faisal Mushtaq26-Oct-15 22:25
Faisal Mushtaq26-Oct-15 22:25 
Questionsolution file Pin
Maciej Anders3-Dec-13 7:36
Maciej Anders3-Dec-13 7:36 
QuestionRe: solution file Pin
Jeff_Rausch4-Dec-13 9:04
Jeff_Rausch4-Dec-13 9:04 
QuestionDoes this work with multiple files? Pin
masterJalchr17-Dec-12 23:28
masterJalchr17-Dec-12 23:28 
AnswerRe: Does this work with multiple files? Pin
Ahmad Dekmak18-Dec-12 0:00
Ahmad Dekmak18-Dec-12 0:00 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.