PlUpload Handler for ASP.NET Core Application

  • 05 December 2018

PlUpload is a popular multi-runtime file uploader that can allow you to upload any type of files via web & mobile devices

This article provide detail how you can process uloaded files directly or via chunk upload within asp.net core application and send response after completing uploads

Sample code to initialize PlUpload within your project through jQuery.

     $("#uploader").pluploadQueue({
        // General settings
        runtimes : 'html5,flash,silverlight,html4',
        url : '/api/uploader/uploads',
        chunk_size : '1mb',
        unique_names : true,
 
        // Resize images on client-side if we can
        resize : {width : 320, height : 240, quality : 90}
    });

To process and save files locally, you have to write api call to receive chunk data and save it on server.

Complete code for processing chunk data within asp.net core application below.

Example Code

This code has been tested in ASP.NET Core 2.1

Create api controller e.g uploaderController and put below actions into it.

      [HttpPost("uploads")]
       public async Task uploads()
        {
            if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType))
            {
                return BadRequest($"Expected a multipart request, but got {Request.ContentType}");
            }
            
            // fetch username from header if you want to receive username and create directory for user
            StringValues UserName;
            SiteConfig.HttpContextAccessor.HttpContext.Request.Headers.TryGetValue("UName", out UserName);

            // Used to accumulate all the form url encoded key value pairs in the 
            // request.
            var formAccumulator = new KeyValueAccumulator();
            // string targetFilePath = null;

            var boundary = MultipartRequestHelper.GetBoundary(
                  MediaTypeHeaderValue.Parse(Request.ContentType),
                  _defaultFormOptions.MultipartBoundaryLengthLimit);

            var reader = new MultipartReader(boundary, HttpContext.Request.Body);

            var section = await reader.ReadNextSectionAsync();

            var uploadPath = SiteConfig.Environment.ContentRootPath + "/wwwroot/uploads";
            if (!Directory.Exists(uploadPath))
            {
                Directory_Process.CreateRequiredDirectories(uploadPath);
            }

            var fileName = "";
            while (section != null)
            {
                ContentDispositionHeaderValue contentDisposition;
                var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition,
                    out contentDisposition);

                if (hasContentDispositionHeader)
                {
                    if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition))
                    {
                        var output = formAccumulator.GetResults();
                        var chunk = "0";
                        foreach (var item in output)
                        {
                            if (item.Key == "name")
                                fileName = item.Value;
                            else if (item.Key == "chunk")
                                chunk = item.Value;
                        }

                        var Path = uploadPath + "" + fileName;
                        using (var fs = new FileStream(Path, chunk == "0" ? FileMode.Create : FileMode.Append))
                        {
                            await section.Body.CopyToAsync(fs);
                            fs.Flush();
                        }
                    }
                    else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition))
                    {
                        var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name);
                        var encoding = GetEncoding(section);
                        using (var streamReader = new StreamReader(
                            section.Body,
                            encoding,
                            detectEncodingFromByteOrderMarks: true,
                            bufferSize: 1024,
                            leaveOpen: true))
                        {
                            // The value length limit is enforced by MultipartBodyLengthLimit
                            var value = await streamReader.ReadToEndAsync();
                            if (String.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase))
                            {
                                value = String.Empty;
                            }
                            formAccumulator.Append(key.ToString(), value);

                            if (formAccumulator.ValueCount > _defaultFormOptions.ValueCountLimit)
                            {
                                throw new InvalidDataException($"Form key count limit {_defaultFormOptions.ValueCountLimit} exceeded.");
                            }
                        }
                    }
                }

                var result = formAccumulator.GetResults();

                // Drains any remaining section body that has not been consumed and
                // reads the headers for the next section.
                section = await reader.ReadNextSectionAsync();
            }

            string orignalfilename = uploadPath + "" + fileName;
           
            string url = "/" + fileName; // url of upload file
            string fileType = System.IO.Path.GetExtension(fileName);
            string fileIndex = fileName.Replace(fileType, "");

            return Ok(new { jsonrpc = "2.0", result = "OK", fname = fileName, url = url, filetype = fileType, filename = fileName, fileIndex = fileIndex });
        }

private static Encoding GetEncoding(MultipartSection section)
{
    MediaTypeHeaderValue mediaType;
    var hasMediaTypeHeader = MediaTypeHeaderValue.TryParse(section.ContentType, out mediaType);
    // UTF-7 is insecure and should not be honored. UTF-8 will succeed in 
    // most cases.
    if (!hasMediaTypeHeader || Encoding.UTF7.Equals(mediaType.Encoding))
    {
       return Encoding.UTF8;
    }
    return mediaType.Encoding;
}

This function will process chunk data and send response back to application when done.