0

I would like to call a RESTfull service using the POST Method in my windows phone 8 app. So I need to insert the datas that I want to send in the body of the request after parsing it to JSON. To do so, I've used the following code:

enter cprivate void NextArrow_Tap(object sender, System.Windows.Input.GestureEventArgs e)
    {
        if (!String.IsNullOrEmpty(TxtBox_mail.Text))
        {
           Uri myUri = new Uri("http://myUri");
           HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(myUri);
           myRequest.Method = "POST";
           myRequest.ContentType = "application/json";
           myRequest.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), myRequest);


        }
    }


    public void GetRequestStreamCallback(IAsyncResult callbackResult)
    {
        byte[] byteArray = null;
        HttpWebRequest myRequest = (HttpWebRequest)callbackResult.AsyncState;

        // End the stream request operation
        Stream postStream = myRequest.EndGetRequestStream(callbackResult);

        // Create the post data
        Dispatcher.BeginInvoke(() =>
        {
            string mailToCheck = TxtBox_mail.Text.ToString();
            string postData = JsonConvert.SerializeObject(mailToCheck);
            byteArray = Encoding.UTF8.GetBytes(postData);
        });


        // Add the post data to the web request
        postStream.Write(byteArray, 0, byteArray.Length);
        postStream.Close();

        // Start the web request
        myRequest.BeginGetResponse(new AsyncCallback(GetResponsetStreamCallback), myRequest);
    }

I've used the dispatcher to get the value of the textbox control on the UI Thread but the byteArray is always null. Somebody knows what could be wrong here ? Thanks in advance.

Hubert Solecki
  • 2,611
  • 5
  • 31
  • 63
  • `byteArray = Encoding.UTF8.GetBytes(postData);` what is postData? Does it contain the string you're expecting? Use `Debug.WriteLine()` to output it's value. – Sjips Nov 09 '14 at 23:14

1 Answers1

3

The main problem is that you are using the asynchronous BeginInvoke() method, which returns immediately. The invoked delegate isn't executed until later, and so the byteArray variable is still null when the current thread moves on to trying to write the data.

One way to fix it would be to use the Invoke() method instead. That method is synchronous; that is, it won't return until the code being invoked has completed.

IMHO, the better way to address it is to use the async/await pattern. That would look something like this:

async void NextArrow_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
    if (!String.IsNullOrEmpty(TxtBox_mail.Text))
    {
       Uri myUri = new Uri("http://myUri");
       HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(myUri);

       myRequest.Method = "POST";
       myRequest.ContentType = "application/json";

       Stream postStream = await myRequest.GetRequestStreamAsync();
       HttpWebResponse response = await GetRequestStreamCallback(postStream, myRequest);

       // await GetResponsetStreamCallback(response) here...the
       // method wasn't shown in the original question, so I've left
       // out the particulars, as an exercise for the reader. :)
    }
}


async void GetRequestStreamCallback(Stream postStream, WebRequest myRequest)
{
    byte[] byteArray = null;

    // Create the post data
    string mailToCheck = TxtBox_mail.Text.ToString();
    string postData = JsonConvert.SerializeObject(mailToCheck);
    byteArray = Encoding.UTF8.GetBytes(postData);

    // Add the post data to the web request
    postStream.Write(byteArray, 0, byteArray.Length);
    postStream.Close();

    // Start the web request
    return await myRequest.GetResponseAsync();
}

As you can see, doing it this way allows the main flow of the code to be written in a plain, direct and sequential manner, making it easier to see where the flow of execution is, and simplifying the expression of the logic overall.

Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
  • myRequest.GetResponseAsync() -- how are you getting that to work? It will be undefined. – Chubosaurus Software Nov 10 '14 at 01:32
  • As I know GetBytes is not thread-safe. It will be better to use local variable instead. – ceth Nov 10 '14 at 03:15
  • @ChubosaurusSoftware: you are correct...one of the hazards of using a browser to type in code. :) Still, I assume that the necessary fix is relatively obvious. I've added it to the post, for those who can't figure it out. – Peter Duniho Nov 10 '14 at 06:55
  • @demas: I have no idea what you mean. `Encoding.UTF8.GetBytes()` is thread-safe (uses no mutable state that might be shared with another thread), and it's not clear what "local variable" you would use instead in any case. – Peter Duniho Nov 10 '14 at 06:58
  • Thanks for that great answer ! For the first fix, the thing is that the method Invoke() does not exists for Windows Phone, only BeginInvoke().. As you told me @Peter Duniho, that method returns immeditalty, that's why I get nothing. I'm going to try your synchronous solution but I'm not sur that the method GetRequestStreamAsync exists as well... I'll will keepyou informed of what I found out :) – Hubert Solecki Nov 10 '14 at 08:52
  • 1
    @HubertSolecki: ah, right. You're right, no Invoke() on WP. But at least according to the docs, you should have [`GetRequestStreamAsync()`](http://msdn.microsoft.com/en-us/library/windows/apps/system.net.httpwebrequest.getrequeststreamasync(v=vs.105).aspx). That's assuming you're on WP 8.1. If not, then IMHO the best alternative is to skip the `BeginInvoke()` altogether; i.e. the only reason you're doing that is to get data from the GUI, but you could just as easily retrieve those values on the initial tap event and create the byte array you'll need later while you're still on the UI thread. – Peter Duniho Nov 10 '14 at 15:20