Thursday 19 January 2017

Upload multiple values including images and keys from windows form to Web Api controller

In this post we are going to see how to upload multiple values including images and keys from the Windows Forms client to Web Api controller. We are going to see how to send the multiple values as well as how to read that multi type values in Api controller.

First we will create the Api controller where we will check whether request consists of MimeMultipartContent, then we are read the stream as Async to read the values from the FileData and Formdata, FileData will return the value of file and FormData will return the value of keys and values pairs send from client.

In this example we are reading the values and send back to client and display the values in message box and url in link label.

    public class CheckMimeMultiPart : ActionFilterAttribute
    {
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            if (!actionContext.Request.Content.IsMimeMultipartContent())
            {
            throw new HttpResponseException(System.Net.HttpStatusCode.UnsupportedMediaType);
            }
        }

    }


   public class MultipartFormStreamProvider: MultipartFormDataStreamProvider
    {
        public MultipartFormStreamProvider(string uploadpath):base(uploadpath)
        {

        }

        public override string GetLocalFileName(HttpContentHeaders headers)
        {
            if (headers != null && headers.ContentDisposition != null)
                return headers.ContentDisposition.FileName.TrimEnd('"').TrimStart('"');

            return base.GetLocalFileName(headers);
        }
    }




   public class BlogController : ApiController
    {
        public string Get()
        {
            return "testing";
        }

        [CheckMimeMultiPart]
        public async Task<FilePostResult> Post()
        {
            try
            {
                var path = HttpContext.Current.Server.MapPath("~/img");
                var sprovide = new MultipartFormStreamProvider(path);
                await Request.Content.ReadAsMultipartAsync(sprovide);
             
                var trackingid = sprovide.FormData.GetValues("trackingid")
                                 .FirstOrDefault();
                var description = sprovide.FormData.GetValues("description")
                                  .FirstOrDefault();

                var localfilename = sprovide.FileData.Select(x => x.LocalFileName)
                                   .FirstOrDefault();

                var fileinfo = new FileInfo(localfilename);
                var response = new FilePostResult();

                response.FileName = fileinfo.Name;
                response.Size = fileinfo.Length;
                response.Url = Request.RequestUri.GetLeftPart(UriPartial.Authority) 
                                +"/img/" + response.FileName; ;
                response.TrackingId = trackingid;
                response.Description = description;

                return response;                               
                 
            }catch(Exception ex)
            {
                return new FilePostResult()
                {
                    FileName = "",
                    Size =0,
                    Url = Request.RequestUri.GetLeftPart(UriPartial.Authority)                   
                };
            }

        }

    }


<system.webServer>
    <security>
      <requestFiltering>
        <requestLimits maxAllowedContentLength="30000000" />
      </requestFiltering>
    </security>
</system.webServer>
   
  <system.web>
    <authentication mode="None" />
    <compilation debug="true" targetFramework="4.6.1" />
    <httpRuntime targetFramework="4.6.1" maxRequestLength="30000000"  />  

  </system.web>


In client side how we are sending the multitype values to api, we are using the stringcontent and streamcontent to add inside the MultiPartFormDataContent


   public partial class Form1 : Form
   {

        DialogResult result;

        public delegate void UpdateLink(FilePostResult result);

        public void Update(FilePostResult result)
        {
            linkLabel1.Links.Clear();
            linkLabel1.Text = result.Url;
            linkLabel1.Links.Add(new LinkLabel.Link(0, result.Url.Length, result.Url));

            MessageBox.Show(string.Format("Tracking Id {0},
Description {1}",result.TrackingId,result.Description));
          
        }


        private void LinkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            Process.Start(e.Link.LinkData.ToString());
        }


        public Form1()
        {
            InitializeComponent();
        openFileDialog1.Filter = "Images (*.JPG;*.BMP;*.PNG;*.GIF)|*.JPG;*.BMP;*.PNG;*.GIF";
            openFileDialog1.Multiselect = true;
            openFileDialog1.Title = "Browse images";
            linkLabel1.LinkClicked += LinkLabel1_LinkClicked;
        }


        private void button1_Click(object sender, EventArgs e)
        {          
            result = openFileDialog1.ShowDialog();        
        }


        private void button2_Click(object sender, EventArgs e)
        {
            string address = "http://localhost:57437/api/Blog";
            HttpClient client = new HttpClient();
            if (result == DialogResult.OK)
            {
                try
                {
                    foreach (var item in openFileDialog1.FileNames)
                    {
                        var stream = File.Open(item, FileMode.Open);
                        var multipartcontent = new MultipartFormDataContent();

    multipartcontent.Add(new StreamContent(stream), "\"postimage\""
                              string.Format("\"{0}\"", item));             
     multipartcontent.Add(new StringContent("tr123456"), "trackingid");
     multipartcontent.Add(new StringContent("Steve is a innovative person"), "description");


                        var resulttask = client.PostAsync(address, multipartcontent);

                        resulttask.ContinueWith(x => {
                            if (x.Status == TaskStatus.RanToCompletion)
                            {
                                var response = resulttask.Result;
                                if (response.IsSuccessStatusCode)
                                {

                     var data = response.Content.ReadAsStringAsync().Result;
                     var postresult = JsonConvert.DeserializeObject<FilePostResult>(data);
                     linkLabel1.BeginInvoke(new UpdateLink(Update), postresult);

                                    foreach (var header in response.Content.Headers)
                                    {

             Debug.WriteLine("{0}: {1}", header.Key, string.Join(",", header.Value));
                                   
                                   }
                                }
                                else
                                {

             Debug.WriteLine("Response :" + response.Content.ReadAsStringAsync().Result);
                                
                               }
                            }

                            stream.Dispose();
                        });
                    }
                }
                catch (Exception ex)
                {

                }
            }
        }

    }




Output:








From this post we can learn how to upload multiple type values to Web Api controller from Windows Forms client.