0

I want to interrogate one sensor that returns a JSON Rest Api response. I make Api call every 40 milliseconds but it gave me this error :

in System.Threading.Tasks.Task1.GetResultCore(Boolean waitCompletionNotification) in System.Threading.Tasks.Task1.get_Result()

I have timer where interval = 40. And this is the code how I call tha Api :

 private void Timer(object sender, EventArgs e)
        {
            tmrPollingSick.Stop();

            string strJson = "";
           
            HttpClient client = new HttpClient();
            string baseUrl = "http://9999.99999.99999.8";
            client.BaseAddress = new Uri(baseUrl);
            var contentType = new MediaTypeWithQualityHeaderValue("application/json");
            client.DefaultRequestHeaders.Accept.Add(contentType);
            string strAltezza = string.Empty;
            try
            {
                strJson = "Here I set HEADERS... DATA ect " + Convert.ToChar(34) +
                        "header" + Convert.ToChar(34) + ": {............" 

                var contentData = new StringContent(strJson, System.Text.Encoding.UTF8, "application/json");
                using (var responseMessage = client.PostAsync("/bla/bla/bla", contentData).Result)
                {
                    if (responseMessage.IsSuccessStatusCode)
                    {
                        string strContext = responseMessage.Content.ReadAsStringAsync().Result;

                        Object dec = JsonConvert.DeserializeObject(strContext);     // deserializing Json string (it will deserialize Json string)

                        JObject obj = JObject.Parse(strContext);
                        //Process Data In
                        JObject obj1 = JObject.Parse(obj["bla"].ToString());
                        JObject obj2 = JObject.Parse(obj1["processDataIn"].ToString());
                        strAltezza = obj2["1"].ToString();
                        textBox1.Text = strAltezza;

                    }
                }
            }

        catch(WebException ex1)
        {
            MessageBox.Show("web: "+ex1.StackTrace.ToString() + " - " + ex1.Message);
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.StackTrace.ToString() + " - " + ex.Message);
        }
        tmrPollingSick.Start();
    }

Everything works fine but after a while it gives me that error. I allready read this (How to implement real time data for a web page and this) but I haven't tried them yet. Any suggestions how to fix this? Is there another way how to get the result in real-time without crashing?

kvacka
  • 27
  • 1
  • 10
  • 1
    Log and post the *full*. exception, not just parts of it. What you posted contains only 2 lines from the stack trace. Using `.Result` is *definitely* wrong, but right now it's impossible to guess what's actually wrong. You reached the server's throttling limit? Creating a new HttpClient instead of reusing the same instance resulted in socket exhaustion? Some other problem? – Panagiotis Kanavos Oct 01 '20 at 13:33
  • 2
    BTW once you parse a JSON string it make no sense to parse its elements again. In your code though, you use both `JsonConvert` *and* `JObject.Parse`, thus parsing the same response twice. – Panagiotis Kanavos Oct 01 '20 at 13:34
  • Http is not a good choice for this, it builds a connection every time and plus all the overhead... you should consider using SignalR or something similar instead – Patrick Beynio Oct 01 '20 at 14:12
  • @PatrickBeynio instead of Http what what else can I use? – kvacka Oct 02 '20 at 07:30

2 Answers2

0

When you call this method all 40ms you'll run out of send sockets, because you create every time a new HttpClient. Even putting this into a using statement (cause HttpClient implements IDisposable) wouldn't solve this problem, cause the underlying socket will be blocked for 3 minutes from the OS (take a look at this answer for further explanations).

You should split this stuff into some initialization phase where you setup the client, build up the request as far as possible and within this timer method just call the PostAsync() method and check the response.

Oliver
  • 43,366
  • 8
  • 94
  • 151
  • I put it inside `using` and doesn't give me that error anymore. But respons time is 200ms. I don't know how to optimize it – kvacka Oct 02 '20 at 07:29
0

May I baptize this as stubborn pooling?

  1. You don't want to use a timer. What you want is x time between request-response cycles. (This will solve the socket exhaustion).
  2. Split your code into phases (client init, request fetch, response processing). See @Oliver answer.
  3. Make a function to execute everything. And run some sort of infinite foreach loop where you can sleep for x time after calling the fetch function (and the process, but you could defer this to another thread or do it async).
Pedro Rodrigues
  • 2,520
  • 2
  • 27
  • 26