1

Here's my code:

namespace RequestApi
{
    public partial class MainPage : PhoneApplicationPage
    {
        private BackgroundWorker bw;
        private string ans;
        private JObject ansJson;
        private static ManualResetEvent allDone = new ManualResetEvent(false);
        // Constructor
        public MainPage()
        {
            InitializeComponent();

        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            string url = "http://192.168.0.43:8182/Account/SignIn";
            CreateRequest(url);

            userId.Text = ansJson.Value<int>("user_id").ToString();

        }


        private void CreateRequest(string url)
        {
            Debug.WriteLine("CreateRequest");
            HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(url);
            req.ContentType = "application/json";
            req.Method = "POST";
            req.BeginGetRequestStream(new AsyncCallback(RequestCallback), req);
            allDone.WaitOne();
        }

        private  void RequestCallback(IAsyncResult aresult)
        {
            Debug.WriteLine("RequestCallback");
            HttpWebRequest req = (HttpWebRequest)aresult.AsyncState;
            Stream postStream = req.EndGetRequestStream(aresult);

            string obj = "{ 'username': 'test_2@aragast.com', 'password': 'a123456' }";
            JObject json = JObject.Parse(obj);
            string s = JsonConvert.SerializeObject(json);
            byte[] postdata = System.Text.Encoding.Unicode.GetBytes(s);

            postStream.Write(postdata, 0, postdata.Length);
            postStream.Close();

            req.BeginGetResponse(new AsyncCallback(ResponseCallback), req);


        }

        private  void ResponseCallback(IAsyncResult aresult)
        {
            Debug.WriteLine("ResponseCallback");
            HttpWebRequest req = (HttpWebRequest)aresult.AsyncState;
            HttpWebResponse resp = (HttpWebResponse)req.EndGetResponse(aresult);
            StreamReader reader = new StreamReader(resp.GetResponseStream());
            string response = reader.ReadToEnd();
            Debug.WriteLine(response);
            JObject responseJson = JObject.Parse(response);
            ansJson = responseJson;
            Debug.WriteLine("ansJson from responseCallback {0}", ansJson);
            reader.Close();
            resp.Close();
            allDone.Set();

        }
    }
}

When I debug application it entered CreateRequest then it enter RequestCallback, but then it stop and never enter ResponseCallback instead it tryis userId.Text to assign asnJson value which is null, because it doesn't enter ResponseCallback. When I do wrong, and why it never enter ResponseCallback?

Aram Gevorgyan
  • 2,175
  • 7
  • 37
  • 57

2 Answers2

2

Your ManualResetEvent is created with true as the argument, so it's already signalled to start with. That means the allDone.Wait() call will immediately continue... so CreateRequest will finish, and you'll immediately try to use the asnJson variable, which as you've said is null. That will kill the application, I suspect - so you never get a chance to get a response.

Now, the solution to this is not to change the ManualResetEvent constructor - you shouldn't be waiting like that in the UI thread anyway! You'll block it, and you've removed the whole point of Windows Phone 7 making everything asynchronous to start with.

Instead, your callbacks should use the dispatcher to call back into the UI thread when they've finished. Note that you should also have robust error handling in case anything goes wrong with the request.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • No it is false, I just mistaken and write here true. But indeed it is false, but I although can't rich the ResponseCallback when I step down with debug I reach this line req.BeginGetResponse(new AsyncCallback(ResponseCallback), req); and then it doesn't move anywhere – Aram Gevorgyan Oct 06 '11 at 16:51
  • @AramGevorgyan: Then maybe it's failing *because* you're blocking the UI thread. You really, really shouldn't be doing that. Change the code so that the response callback triggers the remaining UI code, and see whether it still fails. – Jon Skeet Oct 06 '11 at 16:53
  • Yes, when I don't block Ui thread it enter ResponseCallback, but it enter late before it it do userId.Text = ansJson.Value("user_id").ToString(); which is null, so I must someway wait for the response so I block UI thread. How should I do that? – Aram Gevorgyan Oct 06 '11 at 16:56
  • @AramGevorgyan: You don't block the UI thread - you move the bit of code using `ansJson` into another callback which is only executed when the response completes - use Dispatcher.BeginInvoke` from the response callback to execute it on the UI thread. – Jon Skeet Oct 06 '11 at 16:59
  • Thanks, now it works. Just before I try what you say but get some error. – Aram Gevorgyan Oct 06 '11 at 17:06
1

Not exactly related to answering the question, but an answer block seems to be the only place to fit the recommendation I'm about to make... You should have appropriate resource protection around your streams by employing using blocks as such:

Original code:

        Stream postStream = req.EndGetRequestStream(aresult);

        string obj = "{ 'username': 'test_2@aragast.com', 'password': 'a123456' }";
        JObject json = JObject.Parse(obj);
        string s = JsonConvert.SerializeObject(json);
        byte[] postdata = System.Text.Encoding.Unicode.GetBytes(s);

        postStream.Write(postdata, 0, postdata.Length);
        postStream.Close();

New code (also make sure your encoding is correct for the request: is your web service really expecting UTF-16? It's more common that web servers use UTF-8 (Encoding.UTF8)) :

        using (Stream postStream = req.EndGetRequestStream(aresult))
        {
            string obj = "{ 'username': 'test_2@aragast.com', 'password': 'a123456' }";
            JObject json = JObject.Parse(obj);
            string s = JsonConvert.SerializeObject(json);
            byte[] postdata = System.Text.Encoding.Unicode.GetBytes(s);

            postStream.Write(postdata, 0, postdata.Length);
        }

Original code:

        HttpWebResponse resp = (HttpWebResponse)req.EndGetResponse(aresult);
        StreamReader reader = new StreamReader(resp.GetResponseStream());
        string response = reader.ReadToEnd();
        Debug.WriteLine(response);
        JObject responseJson = JObject.Parse(response);
        ansJson = responseJson;
        Debug.WriteLine("ansJson from responseCallback {0}", ansJson);
        reader.Close();
        resp.Close();

New code:

        using (HttpWebResponse resp = (HttpWebResponse)req.EndGetResponse(aresult))
        using (StreamReader reader = new StreamReader(resp.GetResponseStream()))
        {
            string response = reader.ReadToEnd();
            Debug.WriteLine(response);
            JObject responseJson = JObject.Parse(response);
            ansJson = responseJson;
            Debug.WriteLine("ansJson from responseCallback {0}", ansJson);
        }

I would also recommend surrounding your req and resp operations with try..catch blocks to allow something to process exceptional conditions -- otherwise it will bubble up to the AppDomain's exception handler (can also be hooked by the UnhandledException event).

Jesse C. Slicer
  • 19,901
  • 3
  • 68
  • 87
  • Thank you very much for advice. Yes ther is no problem with utf-16 server get these request and resspond correct response. About try catch you are completely right and it's good idea about using, but it's test application, and I just write it to test some things before staring writeing more complex application, so here it's not so much important about try catch. – Aram Gevorgyan Oct 06 '11 at 18:43