9

I am new to C# so I was wondering if someone can help me out on this. I am trying to send HttpPost from Windows Phone 8 to the server. I found two examples that I would like to combine.

The first one is an example of sending Http Post (http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.begingetrequeststream.aspx). The problem with this one is that it is not support by Windows Phone 8.

The second example is using the BeginGetResponse (http://msdn.microsoft.com/en-us/library/windowsphone/develop/system.net.httpwebrequest(v=vs.105).aspx). This supports windows phone 8.

I need to convert the second example into a BeginGetRequestStream() like the first example. I will try to figure out this myself, but I am posting online if someone already knows how to do this. I am sure this will be helpful for other WP8 developers.

Update I am now trying to get response from the server. I have started a new question. Please follow this link (Http Post Get Response Error for Windows Phone 8)

Community
  • 1
  • 1

2 Answers2

14

I am also currently working on a Windows Phone 8 project and here is how I am posting to a server. Windows Phone 8 sort of has limited access to the full .NET capabilities and most guide I read say you need to be using the async versions of all the functions.

// server to POST to
string url = "myserver.com/path/to/my/post";

// HTTP web request
var httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.ContentType = "text/plain; charset=utf-8";
httpWebRequest.Method = "POST";

// Write the request Asynchronously 
using (var stream = await Task.Factory.FromAsync<Stream>(httpWebRequest.BeginGetRequestStream,          
                                                         httpWebRequest.EndGetRequestStream, null))
{
   //create some json string
   string json = "{ \"my\" : \"json\" }";

   // convert json to byte array
   byte[] jsonAsBytes = Encoding.UTF8.GetBytes(json);

   // Write the bytes to the stream
   await stream.WriteAsync(jsonAsBytes, 0, jsonAsBytes.Length);
}
Hunter McMillen
  • 59,865
  • 24
  • 119
  • 170
  • 4
    this is so much simplier and easier to understand as a c# newbie. since you are using `await`, would it be correct that if i call a function after that line, it means that the data was sent successfully? (how you get response from server?).. –  Feb 05 '13 at 05:17
  • Hi @Hunter MCmillen, Your above code is working successfully ? I am asking because i have tried twice to it but it shows the NotFound exception. – Ashish-BeJovial Feb 06 '14 at 07:45
  • Are you replacing the URL with a real address? `myserver.com` is not a real site, but just an example – Hunter McMillen Feb 06 '14 at 13:59
  • Hi @HunterMcMillen, I'm trying your solution but `httpWebRequest.ContentLength` is always -1 (and _ContentLength = 0) after writing and Request.ContentLength on my server is also zero. Can you help me ? – SeyoS Mar 04 '15 at 14:25
6

I propose a more generic asynchronous approach supporting success and error callbacks here:

//Our generic success callback accepts a stream - to read whatever got sent back from server
public delegate void RESTSuccessCallback(Stream stream);
//the generic fail callback accepts a string - possible dynamic /hardcoded error/exception message from client side
public delegate void RESTErrorCallback(String reason);

public void post(Uri uri,  Dictionary<String, String> post_params, Dictionary<String, String> extra_headers, RESTSuccessCallback success_callback, RESTErrorCallback error_callback)
{
    HttpWebRequest request = WebRequest.CreateHttp(uri);
    //we could move the content-type into a function argument too.
    request.ContentType = "application/x-www-form-urlencoded";
    request.Method = "POST";

    //this might be helpful for APIs that require setting custom headers...
    if (extra_headers != null)
        foreach (String header in extra_headers.Keys)
            try
            {
                request.Headers[header] = extra_headers[header];
            }
            catch (Exception) { }


    //we first obtain an input stream to which to write the body of the HTTP POST
    request.BeginGetRequestStream((IAsyncResult result) =>
    {
        HttpWebRequest preq = result.AsyncState as HttpWebRequest;
        if (preq != null)
        {
            Stream postStream = preq.EndGetRequestStream(result);

            //allow for dynamic spec of post body
            StringBuilder postParamBuilder = new StringBuilder();
            if (post_params != null)
                foreach (String key in post_params.Keys)
                    postParamBuilder.Append(String.Format("{0}={1}&", key, post_params[key]));

            Byte[] byteArray = Encoding.UTF8.GetBytes(postParamBuilder.ToString());

            //guess one could just accept a byte[] [via function argument] for arbitrary data types - images, audio,...
            postStream.Write(byteArray, 0, byteArray.Length);
            postStream.Close();


            //we can then finalize the request...
            preq.BeginGetResponse((IAsyncResult final_result) =>
            {
                HttpWebRequest req = final_result.AsyncState as HttpWebRequest;
                if (req != null)
                {
                    try
                    {
                        //we call the success callback as long as we get a response stream
                        WebResponse response = req.EndGetResponse(final_result);
                        success_callback(response.GetResponseStream());
                    }
                    catch (WebException e)
                    {
                        //otherwise call the error/failure callback
                        error_callback(e.Message);
                        return;
                    }
                }
            }, preq);
        }
    }, request);            
}
JWL
  • 13,591
  • 7
  • 57
  • 63
  • @AshishJain, yes it does. Actually, I've used it in my 3 WP8 apps now on the store (MyChild, MyStudents, MySchool). An updated version of this generic code is also on my gists here: https://gist.github.com/mcnemesis/6250994 – JWL Feb 06 '14 at 09:29
  • 1
    `using System.Security.Cryptography;` `using System.Text;` These additional namespaces are required. – rahulroy9202 Feb 14 '14 at 09:30
  • How would I return a string from this post function without going through the delegate? – Jimmyt1988 Apr 15 '14 at 20:08
  • @Jimmyt1988 as it is right now,that would require that u modify the definition of that function so as to make the *actual* posting synchronous so that the thread blocks until the request is complete, and then u could return the response in the main function. Otherwise, I currently use the callback approach to be able to accommodate the asynchronous nature of the implementation. Though, for the majority of IO APIs of WP8, it's recommended to work in async mode - the reasons make sense. – JWL Apr 16 '14 at 06:19
  • Thank you for this. It's probably the first sensible solution I've seen given to HTTP post requests in Windows Phone 8, i.e. no ManualResetEvents or crazy async method chains or HTTPClient. – Toby Jul 01 '14 at 05:35
  • postParamBuilder.Append(String.Format("&{0}={1}", key, post_params[key])); Current code doesn't support multiple params, adding the & to the beginning of the string fixes. – Toby Jul 01 '14 at 05:52
  • @Toby thanks for the reminder, actually, in the linked implementation, I'd earlier on fixed this, with `{0}={1}&`, which I now fix here as well. Cheers! – JWL Jul 01 '14 at 10:46