2

I have a code where I am creating an instance of HttpClient, which is inside of a foreach loop. Which means it is creating a new instance for each time the iteration takes place. Here is my code :

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Net.Http.Headers;
using System.Net.Http;
using System.Text;
using System.Net.Mime;
using System.Net.Http.Json;

public class Program
   {
        static async Task Main(string[] args)
        {
            //JSON String
            string json = @"{
            'Values': [
                {
                    'MsgSource': null,
                    'TagName': 'Data.New_MSG',
                    'RawValue': '[\r\n  {\r\n    \'ID\': 145,\r\n    \'StationNo\': 6,\r\n    
                                 \'RunTime\': 1800,\r\n    \'ControllerID\': 4,\r\n    
                                 \'ControllerAddress\': 2,\r\n    \'ProgramNo\': 2,\r\n    
                                 \'ModeID\': \'AutoProgram\',\r\n    \'EventDate\': \'2022-04- 
                                 27T23:30:02\',\r\n    \'Description\': \'Irrigation 
                                 Completed\',\r\n    \'MessageCode\': 5\r\n,\r\n    
                                 \'ControllerName\': \'P25-SC-0233\'  },\r\n  {\r\n    \'ID\': 
                                 144,\r\n    \'StationNo\': 18,\r\n    \'RunTime\': 1800,\r\n    
                                 \'ControllerID\': 4,\r\n    \'ControllerAddress\': 2,\r\n    
                                 \'ProgramNo\': 5,\r\n    \'ModeID\': \'AutoProgram\',\r\n    
                                 \'EventDate\': \'2022-04-27T22:00:00\',\r\n    \'Description\': 
                                 \'Irrigation Completed\',\r\n    \'MessageCode\': 5\r\n,\r\n    
                                 \'ControllerName\': \'P25-SC-0226\'  }\r\n]',
                    'Status': 'Normal',
                    'ComStatus': null,
                    'TimeStamp': '2022-04-28 13:17:39.851'
                }
                ]
            }";

            //Deserializing JSON String
            Root root = JsonConvert.DeserializeObject<Root>(json);
            //Extracting the value of only RawValue key from the String
            string rawValue = root.Values[0].RawValue;

            //Creating List of ControllerName key            
            List<Station> stations = JsonConvert.DeserializeObject<List<Station>>(rawValue);
            
            JArray array = JArray.Parse(rawValue);
            
            int i = 0;    //Initializing Index to add ControllerName to the URL in Get http 
                          //request below
            foreach(var item in array) //Iterating through array
            {
                
                  var inc_val = i++;
                
                  using (var client = new HttpClient()) //Here I've Instantiated HttpClient
                  {
                    
                    client.DefaultRequestHeaders.Authorization = new 
                    AuthenticationHeaderValue("Basic","auth_value"); //Basic Auth

                    //Mandatory key for Message body in Post request
                    string isoTime = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
                    
                    //Concatenating ControllerName in URL and making get request
                    HttpResponseMessage get_response = await 
                    client.GetAsync("https://myurl.com/"+stations[inc_val]);

                    var get_responseString = await get_response.Content.ReadAsStringAsync();

                    JObject obj = JObject.Parse(get_responseString);

                    //Extracting id from the response of Get request which has to be used in
                    //Post Data when making Post request
                    string name = (string) obj["managedObject"]["id"];

                    //Required JSON Body structure which needs to be merged with Post Data
                    string json2 =    $"{{\"time\": \"{isoTime}\",\"source\": {{\"id\": \"{name}\" 
                    }},\"type\": \"c8y_Golf_Controller\",\"text\": \"PilotCC Data New Msg\"}}";

                    JObject json3 = JObject.Parse(json2);
                    var result = new JObject();
                    result.Merge(item);
                    result.Merge(json3);
                    string json4 = JsonConvert.SerializeObject(result);
                    
                    client.DefaultRequestHeaders.Add("Accept", 
                    "application/vnd.com.nsn.cumulocity.event+json"); //More Headers
                    
                    var stringContent = new StringContent(json4, Encoding.UTF8, 
                    "application/json");
                    
                    stringContent.Headers.ContentType.CharSet = "";

                    //Making Post request                    
                    HttpResponseMessage response = await client.PostAsync("https://myurl.com", 
                    stringContent);

                    var responseString = await response.Content.ReadAsStringAsync();

                    Console.WriteLine(responseString);
                }
          }

     }
        
      public class Root
      {
          public List<Value> Values {get; set;}
      }
      public class Value
      {
          public string RawValue { get; set; }
      }

      public class Station
      {
            [JsonProperty("ControllerName")]
            public string ControllerName { get; set; }

            public override string ToString()
            {
               return String.Format(ControllerName);
            }
      }        
}

How do I make it better by not creating unnecessary instances of HttpClient each time foreach loop iteration in triggered and instead reuse the single instance of HttpClient for making all the http requests??

5
  • 2
    Store it in a variable outside the loop. That's all you need to do. If you need to modify headers, do so in the HttpRequestMessage, not the HttpClient.DefaultRequestHeaders Commented May 18, 2022 at 13:35
  • 1
    Instead of using string concatenation to create a JSON string use JSON.NET to serialize, deserialize or modify. String concatenation uses more RAM, is slower and introduces errors Commented May 18, 2022 at 13:37
  • @PanagiotisKanavos Is this in relation to the Concatenation I'm doing in the URL? Or for what I'm doing here var result = new JObject(); result.Merge(item); result.Merge(json3);?? Commented May 18, 2022 at 13:46
  • You should read up on HttpClientFactory. HttpClient has interesting lifecycle behavior (one example, it's disposable, but you shouldn't normally dispose it). The client factory understands all this and manages the details for you Commented May 18, 2022 at 13:57
  • @Flydog57 I'll surely go through it. Thanks Commented May 18, 2022 at 16:46

1 Answer 1

3

In your case, it would be enough to ...

public class Program
{
    static async Task Main()
    {
         // Create one single instance outside the loop ...
         var client = new HttpClient();

         // more code here

         foreach( var item in array ) 
         {
             // ... then use it.
             var response = await client.GetAsync(/* yadda yadda */);
         }
    }
}
Sign up to request clarification or add additional context in comments.

5 Comments

When going into second iteration, it's throwing an error : Unhandled exception. Newtonsoft.Json.JsonReaderException: Error reading JObject from JsonReader. Path '', line 0, position 0. at Newtonsoft.Json.Linq.JObject.Load(JsonReader reader, JsonLoadSettings settings) at Newtonsoft.Json.Linq.JObject.Parse(String json, JsonLoadSettings settings) at Newtonsoft.Json.Linq.JObject.Parse(String json) at Program.Main(String[] args) in D:\Projects\sagemcomm\deserializeJSON\Program.cs:line 74 at Program.<Main>(String[] args)
Line 74 : JObject obj = JObject.Parse(get_responseString);
That's a different issue. Check if you are getting an actual valid json string, there.
I've tried to print the value of Console.WriteLine(stations[inc_val]); First time it gives P25-SC-0233 and valid json response is coming. Second time it's printing P25-SC-0226 as expected but after that no response and eventually the error which I gave above. Although I used Same API in Postman with P25-SC-0226 ID and it's successfully returning proper JSON response there.
And as I reversed back to the original implementation of HttpClient I'm receiving JSON response on both the iterations of getasync

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.