Tuesday, October 11, 2016

How to upload a file with progress indicator using WEB API

I really wanted to put a very simple example on how you can upload a file using Web API and get a progress indicator on the client. The client code here is using a console application, but I tested the code with portable libraries and it should work just fine. This is not production code! there is no security, not error handling, this is the code I used to prototype and decided to share it, it is a bare bones example.

Server code

Controller code

   public class ValuesController : ApiController
   {
        [HttpGet]
        [Route("upload/movie")]
        public string SayHello()
        {
            return "Hello World";

        }

        /// 
        /// Upload a file 
        /// 
        /// The file information
        [HttpPost]
        [Route("upload/movie")]
        [ResponseType(typeof(List))]
        public async Task SaveFileAttachment()
        {
            List model = await FileUploader.UploadAttachment(Request);
            return Request.CreateResponse(HttpStatusCode.Created, model);
        }


    }

The helper code on the server to upload a file

  public class FileUploader
  {
        const string UPLOAD_PATH = "C:\\UPLOAD";
        public static async Task> UploadAttachment(HttpRequestMessage request)
        {
            
            // Verify that this is a file upload request
            if (!request.Content.IsMimeMultipartContent())
            {
                throw new HttpResponseException(request.CreateResponse(HttpStatusCode.UnsupportedMediaType));
            }

            // Create a stream provider for setting up output streams
            var streamProvider = new MultipartFormDataStreamProvider(UPLOAD_PATH);
            MultipartFormDataStreamProvider resultProvider = null; 

            try
            {
                resultProvider = await request.Content.ReadAsMultipartAsync(streamProvider);
                
            }
            catch(Exception ex)
            {
                var x = ex.Message; // for debugging
                throw ex;
            }
          
            var files = new List();

            // Collect uploaded files
            foreach (MultipartFileData file in resultProvider.FileData)
            {
                string localFileName = Path.GetFileName(file.LocalFileName);
                string originalFileName = file.Headers.ContentDisposition.FileName;
                if (string.IsNullOrEmpty(localFileName) || string.IsNullOrEmpty(originalFileName))
                {
                    continue;
                }

                string fileName = originalFileName.Trim().Trim('"');
                files.Add(new FileUploadModel
                {
                    FileName = fileName,
                    LocalFullPath = Path.Combine(UPLOAD_PATH, localFileName),
                    Comment = String.Empty
                });
            }
            return files;
        }
    }

The client code

Console Application (notice there is a callback here to get the updated status)
 class Program
    {
        static void Main(string[] args)
        {
            string fileName = @"C:\Users\Public\Videos\Sample Videos\Wildlife.wmv";

            FileStream stream = File.Open(fileName, FileMode.Open);
            
            var response = UploadMe.UploadFile(stream, "Wild Life - uploaded.wmv", (progress) => { Console.WriteLine(progress); });
            
            Console.ReadLine();
        }

Client Helper

  public class UploadMe
    {           
        public static async Task> UploadFile(Stream fileStream, string fileName, Action callback)
        {

            ProgressMessageHandler progress = new ProgressMessageHandler();
            progress.HttpSendProgress += new EventHandler((e, args) => { callback(args.ProgressPercentage); });

            MultipartFormDataContent content = new MultipartFormDataContent();

            // the request
            HttpRequestMessage message = new HttpRequestMessage();

            content.Add(new StreamContent(fileStream), "file", fileName);


            message.Method = HttpMethod.Post;
            message.Content = content;
            message.RequestUri = new Uri("http://localhost/UploadFileNoSecurity/upload/movie");


            var client = HttpClientFactory.Create(progress);
            client.Timeout = TimeSpan.FromHours(1);

            var response = await client.SendAsync(message);

            if (response.IsSuccessStatusCode)
            {
                Task httpResponse = response.Content.ReadAsStringAsync();
                List json = JsonConvert.DeserializeObject>(httpResponse.Result);
                return json;

            }

            return null;            
        }

    }

The DTO code

namespace UploadModel
{
    public class FileUploadModel
    {
     
        public string FileName { get; set; }

     
        public string LocalFullPath { get; set; }

     
        public string Comment { get; set; }
    }
}

1 comment:

Smith said...

Hi, Great.. Tutorial is just awesome..It is really helpful for a newbie like me.. I am a regular follower of your blog. Really very informative post you shared here. Kindly keep blogging. If anyone wants to become a .Net developer learn from .Net Core Training in Chennai. or learn thru .Net Core Training in Chennai. Nowadays Dot Net has tons of job opportunities on various vertical industry.
or Es6 Training in Chennai. Nowadays JavaScript has tons of job opportunities on various vertical industry.