Main Site Documentation

HttpWebRequest.getresponse() makes button unresponsive


#1

I am using the Gadgeteer FEZ Spider, ENC28 Ethernet module, button module, MF 4.2.
When httpWebRequest.getresponse() is called and the function does not return for many seconds waiting for the web server’s response, pressing the button does not cause the event handler to be called and the LED does not turn on, with Button.LEDModes.OnWhilePressed. I have spawned a thread to call getresponse() but that does not help. I tried calling thread.join(100) and thread.sleep(0) while waiting for the thread to finish, but that does not help. There is no asynchronous version of getresponse() in NETMF. How can I call getresponse() and keep the devices responsive while waiting for a response?
Here is my code:

   private HttpWebRequest reqParam=null;
    private HttpWebResponse respParam=null;

    private HttpWebResponse GetResponseAsync(HttpWebRequest req)
    {
        try
        {
            respParam = null;
            reqParam = req;
            ThreadStart starter = new ThreadStart(getResponseFunction);
            Thread th = new Thread(starter);
            th.Start();
           
            counter = AsyncTimeout/100;
            while (!th.Join(100))
            {
                Thread.Sleep(0);
                --counter;
                if (counter <= 0)
                {
                    th.Abort();
                    throw new System.Net.WebException("HTTP connection timeout");//InvalidOperationException("Timeout!");
                }
            }
        }
        finally
        {
        }
        return respParam;
    }

    private void getResponseFunction()
    {
        try
        {
            respParam = (HttpWebResponse)reqParam.GetResponse();
        }
        catch (Exception) { }
    }

    private WebResponse MakeRequest(string url, object obj, string Method, string id, string key)
    {
        Debug.Print("Request: " + url);
        using (HttpWebRequest req = HttpWebRequest.Create(url) as HttpWebRequest)
        {

            req.Method = Method;
            req.ContentType = ContentType;
            req.KeepAlive = false;
            req.Headers.Add(IdHeader, id);
            req.Headers.Add(KeyHeader, key);
            req.ReadWriteTimeout = AsyncTimeout;
            req.Timeout = AsyncTimeout;
            if (obj != null)
            {
                JsonFormatter js = new JsonFormatter();

                string s = js.ToJson(obj);
                req.ContentLength = s.Length;
                using (Stream rs = req.GetRequestStream())
                {
                    rs.Write(Encoding.UTF8.GetBytes(s), 0, s.Length);
                    rs.Close();
                }
            }

            HttpWebResponse resp = GetResponseAsync(req); //(HttpWebResponse)req.GetResponse(); //
            Debug.Print("Done. Response code = " + resp.StatusCode.ToString());
            return resp;
        }
      
    }

#2

Welcome to the forum.

Can you please wrap your code with the code tags? Hard to read.


#3

        private HttpWebRequest reqParam=null;
        private HttpWebResponse respParam=null;

        private HttpWebResponse GetResponseAsync(HttpWebRequest req)
        {
            try
            {
                respParam = null;
                reqParam = req;
                ThreadStart starter = new ThreadStart(getResponseFunction);
                Thread th = new Thread(starter);
                th.Start();
               
                counter = AsyncTimeout/100;
                while (!th.Join(100))
                {
                    Thread.Sleep(0);
                    --counter;
                    if (counter <= 0)
                    {
                        th.Abort();
                        throw new System.Net.WebException("HTTP connection timeout");//InvalidOperationException("Timeout!");
                    }
                }
            }
            finally
            {
            }
            return respParam;
        }

        private void getResponseFunction()
        {
            try
            {
                respParam = (HttpWebResponse)reqParam.GetResponse();
            }
            catch (Exception) { }
        }

        private WebResponse MakeRequest(string url, object obj, string Method, string id, string key)
        {
            Debug.Print("Request: " + url);
            using (HttpWebRequest req = HttpWebRequest.Create(url) as HttpWebRequest)
            {

                req.Method = Method;
                req.ContentType = ContentType;
                req.KeepAlive = false;
                req.Headers.Add(IdHeader, id);
                req.Headers.Add(KeyHeader, key);
                req.ReadWriteTimeout = AsyncTimeout;
                req.Timeout = AsyncTimeout;
                if (obj != null)
                {
                    JsonFormatter js = new JsonFormatter();

                    string s = js.ToJson(obj);
                    req.ContentLength = s.Length;
                    using (Stream rs = req.GetRequestStream())
                    {
                        rs.Write(Encoding.UTF8.GetBytes(s), 0, s.Length);
                        rs.Close();
                    }
                }

                HttpWebResponse resp = GetResponseAsync(req); //(HttpWebResponse)req.GetResponse(); //
                Debug.Print("Done. Response code = " + resp.StatusCode.ToString());
                return resp;
            }
          
        }



#4

Your implementation of GetResponseAsync is not actually asynchronous. It spawns a new thread to perform the GetResponse, yes, but it then waits in a loop for the thread to do the work. While it’s in that wait loop, nothing else can happen on the main thread, including button click events.

To be asynchronous, your function needs to spawn a new thread to perform the GetResponse and immediately return to the caller. When the GetResponse thread is finisihed with its work it can/should perform some sort of notification to indicate to the main thread that the work is ready to be picked up, or call a callback function to deliver the results to somewhere of interest.

A traditional async function by definition cannot return a function result like HttpWebResponse because the result won’t be known until the asynchronous work has been completed. An async function typically returns some sort of semaphore or state context (Like IAsyncResult) which can later be used to obtain the result of the async operation.

(The Await syntax in C# 5.0 muddies the waters here by making async stuff look like sequential synchronous execution. Under the hood, the compiler goes through lots of gymnastics to make it all work out. Do not use C# 5.0 as a basis for async modeling unless you are coding in C# 5.0)

-Danny


#5

As a temporary test:
[ol]Add an HttpWebResponse field to your class.
Remove the wait loop from the GetResponseAsync function
Remove the function result from GetResponseAsync (change it to void)
Have the GetResponse child thread store the response in the HttpWebResponse field.
Use a timer on the main thread to periodically check to see if the HttpWebResponse field is non-null. When it’s non-null, you have received the response.[/ol]