Pages

Wednesday 20 May 2015

Windows Phone 8.0: How to post Multipart Data (Text & Image) to a web service (C#-Xaml)

Introduction:

Hi guys I hope all you guys are doing well?. After a long break I am writing this post on my blog and i am really says sorry to my dear visitors, due to my busy work last two months i was not active in my blog. However this post will be explain about 'Multi Part post to webservice in windows phone 8.0' .

This article has following steps:
  •  Read in the byte array contents of the file ( If we are trying to post image to server ) 
  •  Construct the request in the form of dictionary objects ( For both string parameters and image type)
  •  Set up the request message headers /content type
  •  Set the Multipart content of the request 
  •  Send the request to the web service & get the response

Requirements:

  • This sample is targeted on silverlight windowsphone 8.0 OS

Description: 

Okay,lets follow above steps to post multipart data to server .

Step 1:
Open Visual Studio and create new project name (Ex: "MultiPartDataWP8"). And add following xaml code in MainPage.xaml page.

  <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock Text="Post Multipart to a WebService" FontSize="25"/>
        </StackPanel>
        <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            
            <TextBlock Text="Name :" Grid.Row="0" VerticalAlignment="Center"/>
            <TextBox Name="tbxName" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Stretch"  TextWrapping="Wrap"/>
            
            <TextBlock Text="Website :" Grid.Row="1" VerticalAlignment="Center"/>
            <TextBox Name="tbxWebsite" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Stretch" TextWrapping="Wrap"/>
            
            <TextBlock Text="Profile Image" Grid.Row="2" VerticalAlignment="Center"/>
            <Button Name="BtnChooseImage" Grid.Row="2" Grid.Column="1" HorizontalAlignment="Stretch" Content="Choose Image" Click="BtnChooseImage_Click"/>
            <Image Name="imgProfile" Grid.Row="3" Grid.Column="1" HorizontalAlignment="Stretch"/>
       
        </Grid>
       
        <Button Name="BtnSubmit" Grid.Row="2" Grid.Column="1" Content="Submit" Click="BtnSubmit_Click"/>
        <TextBlock Grid.Row="3" VerticalAlignment="Bottom" HorizontalAlignment="Right" Margin="0,0,10,12">
            <Run Text="SubramanyamRaju WindowsPhone Tutorials"/>
            <LineBreak></LineBreak>
            <Run Text="http://bsubramanyamraju.blogspot.com/"/>
        </TextBlock>
    </Grid>

Press 'F5' to run the application, and screen should be launch as like below:


Step 2: Read in the byte array contents of the file
If we want to upload image to server, first we need to get image from gallery and covert it to array of bytes. So from above UI when we press on 'Choose Image' button will redirect to gallery for choosing photo.

 BitmapImage ObjBmpImage = new BitmapImage(); 
        private void BtnChooseImage_Click(object sender, RoutedEventArgs e) 
        { 
            PhotoChooserTask photoChooserTask; 
            photoChooserTask = new PhotoChooserTask(); 
            photoChooserTask.Completed += new EventHandler<PhotoResult>(photoChooserTask_Completed); 
            photoChooserTask.ShowCamera = true; 
            photoChooserTask.Show(); 
        } 
 
        void photoChooserTask_Completed(object sender, PhotoResult e) 
        { 
            if (e.TaskResult == TaskResult.OK) 
            { 
                //Code to display the photo on the page in an image control named myImage. 
                isImageUpload = true; 
                ObjBmpImage.SetSource(e.ChosenPhoto); 
                imgProfile.Source = ObjBmpImage; 
            } 
        }

Below method is for converting our global bitmap object to array of bytes.And this method is useful in next  future steps.

 public byte[] ImageToArray(BitmapImage image) 
        { 
            WriteableBitmap wbmp = new WriteableBitmap(image); 
            MemoryStream ms = new MemoryStream(); 
 
            wbmp.SaveJpeg(ms, wbmp.PixelWidth, wbmp.PixelHeight, 0, 100); 
            return ms.ToArray(); 
 
        } 

Step 3: Construct the request in the form of dictionary objects
 

public void DataUpload(BitmapImage image) 
        { 
            // Generate post objects 
            Dictionary<string, object> postParameters = new Dictionary<string, object>(); 
 
            //String parameters 
            postParameters.Add("Name", tbxName); 
            postParameters.Add("Website", tbxWebsite); 
 
            //Image parameter 
            if (isImageUpload) 
            { 
                bytesImg = ImageToArray(image); 
                byte[] data = bytesImg; 
                postParameters.Add("imgProfile", new FileParameter(data, "leak_image.png", "image/png")); 
            } 
 
            MultipartFormDataPost("WEBSERVICE URL", postParameters);// You should be replace your webservice url here. 
            
        } 

Note: Please replace your webservice URL in above method.
Step 4: Set up the request message headers/content type

Make sure to mention proper content type before requesting to server.

public void MultipartFormDataPost(string postUrl, Dictionary<string, object> postParameters) 
        { 
            string formDataBoundary = String.Format("----------{0:N}", Guid.NewGuid()); 
            string contentType = "multipart/form-data; boundary=" + formDataBoundary; 
 
            byte[] formData = GetMultipartFormData(postParameters, formDataBoundary); 
 
            PostForm(postUrl, contentType, formData); 
        }

Step 5: Set the Multipart content of the request

private static byte[] GetMultipartFormData(Dictionary<string, object> postParameters, string boundary) 
        { 
 
            Stream formDataStream = new System.IO.MemoryStream(); 
            bool needsCLRF = false; 
            try 
            { 
                foreach (var param in postParameters) 
                { 
                    // Thanks to feedback from commenters, add a CRLF to allow multiple parameters to be added. 
                    // Skip it on the first parameter, add it to subsequent parameters. 
                    if (needsCLRF) 
                        formDataStream.Write(encoding.GetBytes("\r\n"), 0, encoding.GetByteCount("\r\n")); 
 
                    needsCLRF = true; 
 
                    if (param.Value is FileParameter) 
                    { 
                        FileParameter fileToUpload = (FileParameter)param.Value; 
 
                        // Add just the first part of this param, since we will write the file data directly to the Stream 
                        string header = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"\r\nContent-Type: {3}\r\n\r\n", 
                            boundary, 
                            param.Key, 
                            fileToUpload.FileName ?? param.Key, 
                            fileToUpload.ContentType ?? "application/octet-stream"); 
 
                        formDataStream.Write(encoding.GetBytes(header), 0, encoding.GetByteCount(header)); 
 
                        // Write the file data directly to the Stream, rather than serializing it to a string. 
                        formDataStream.Write(fileToUpload.File, 0, fileToUpload.File.Length); 
                    } 
                    else 
                    { 
                        string postData = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}", 
                            boundary, 
                            param.Key, 
                            param.Value); 
                        formDataStream.Write(encoding.GetBytes(postData), 0, encoding.GetByteCount(postData)); 
                    } 
                } 
 
                // Add the end of the request.  Start with a newline 
                string footer = "\r\n--" + boundary + "--\r\n"; 
                formDataStream.Write(encoding.GetBytes(footer), 0, encoding.GetByteCount(footer)); 
            } 
            catch (Exception) 
            { 
                throw new Exception("Network Issue"); 
            } 
            // Dump the Stream into a byte[] 
            formDataStream.Position = 0; 
            byte[] formData = new byte[formDataStream.Length]; 
            formDataStream.Read(formData, 0, formData.Length); 
            formDataStream.Close(); 
            return formData; 
        }

Step 6: Send the request to the web service & get response

private void PostForm(string postUrl, string contentType, byte[] formData) 
        { 
            HttpWebRequest httpWebRequest = WebRequest.Create(postUrl) as HttpWebRequest; 
 
            if (httpWebRequest == null) 
            { 
                throw new NullReferenceException("request is not a http request"); 
            } 
 
            // Set up the request properties. 
            httpWebRequest.Method = "POST"; 
            httpWebRequest.ContentType = contentType; 
            httpWebRequest.CookieContainer = new CookieContainer(); 
            httpWebRequest.ContentLength = formData.Length; 
            httpWebRequest.BeginGetRequestStream((result) => 
            { 
                try 
                { 
                    HttpWebRequest request = (HttpWebRequest)result.AsyncState; 
                    using (Stream requestStream = request.EndGetRequestStream(result)) 
                    { 
                        requestStream.Write(formData, 0, formData.Length); 
                        requestStream.Close(); 
                    } 
                    request.BeginGetResponse(a => 
                    { 
                        try 
                        { 
                            var response = request.EndGetResponse(a); 
                            var responseStream = response.GetResponseStream(); 
                            using (var sr = new StreamReader(responseStream)) 
                            { 
                                using (StreamReader streamReader = new StreamReader(response.GetResponseStream())) 
                                { 
                                    string responseString = streamReader.ReadToEnd(); 
 
                                    if (!string.IsNullOrEmpty(responseString)) 
                                    { 
                                        Dispatcher.BeginInvoke(() => 
                                        { 
                                            MessageBox.Show("Your data is successfully submitted!"); 
                                        }); 
                                    } 
                                    else 
                                    { 
                                        Dispatcher.BeginInvoke(() => MessageBox.Show("Error in data submission!")); 
                                    } 
                                     
                                } 
                            } 
                        } 
                        catch (Exception ex) 
                        { 
                            Dispatcher.BeginInvoke(() => 
                            { 
                                MessageBox.Show("Error in data submission!"); 
                            }); 
                        } 
                    }, null); 
                } 
                catch (Exception) 
                { 
                    
                    MessageBox.Show("Error in data submission!"); 
                } 
            }, httpWebRequest); 
 
            isImageUpload = false; 
        }

  


 MultipartWP8

FeedBack Note:
Please share your thoughts,what you think about this post,Is this post really helpful for you?I always welcome if you drop comments on this post and it would be impressive.

Follow me always at @Subramanyam_B
Have a nice day by  :)


    6 comments:


    1. Hi Subramanyam,
      I am facing one issue. I want to send request object (includes byte[] property and other properties) to rest service I am getting bad request from service. I think request doesn't hit server. I am using HttpStringContent to set the content of the HttpRequestMessage. If I remove byte[] property from request object I am able to connect the rest service.

      I am using windows phone 8.1 and Windows.Web.Http classes.

      Could you help me to solve the issue.

      ReplyDelete
    2. Hi
      I am having issues with my textblock content, the content does not show completely.
      Whenever i scroll up is always truncated. i have tried increasing the textblock/scrollviewer hieght is still the same

      see the code below
      xaml










      xaml.cs
      namespace DevotionJson
      {
      public partial class BibleInYear : PhoneApplicationPage
      {

      private List devotions;

      public BibleInYear()
      {
      InitializeComponent();

      devotions = new List();
      AddDevotions();
      }

      protected override void OnNavigatedTo(NavigationEventArgs e)
      {
      DateTime dt = DateTime.Now;
      int month = dt.Month;
      int year = dt.Year;
      int index;

      if (DateTime.IsLeapYear(year) || (month <= 2))
      {
      index = dt.DayOfYear - 1; // list is indexed from 0
      }
      else
      {
      index = dt.DayOfYear; // add a day
      }

      textblock.Text = devotions[index].ToString(); // or some other property
      }

      private void AddDevotions()
      {
      for (int i = 1; i <= 366; i++)
      {
      string filePath = "BibleInYear/Bible" + i.ToString() + ".json";
      BibleData d = ReadJsonFile(filePath);
      devotions.Add(d);
      }
      }

      public BibleData ReadJsonFile(string JsonfilePath)
      {
      BibleData[] d = null;

      using (StreamReader r = new StreamReader(JsonfilePath))
      {
      string json = r.ReadToEnd();
      d = JsonConvert.DeserializeObject(json);
      }
      return d[0];
      }

      }
      }

      Kindly help

      ReplyDelete
    3. I am trying to iplement this in windows 10. I am getting the success response but not getting the proper result of content of response.
      Can you provide the sample for windows10 uwp?

      ReplyDelete
    4. Hi Subramanyam,
      I am useing the same code for desktop app ,responece is success but in server the image is not displaying

      ReplyDelete