0

I have designed the following method to call api within the loop. I was wondering if there is any other better way (performance) of calling APIs multiple times?

 private List<ClientInfo> populateDetails(List<ClientInfo> lstClientDetails)
    {
        using (var client = new HttpClient())
        {
            client.BaseAddress = EndpointAddress;
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            string Uri = "";
            ClientInfo clientInfo;

            foreach (var record in lstClientDetails)
            {
                Uri = string.Format("{0}", record.id);

                var postResponse = client.GetAsync(Uri).Result;

                if (postResponse.IsSuccessStatusCode)
                {
                    string result = postResponse.Content.ReadAsStringAsync().Result;

                    clientInfo = JsonConvert.DeserializeObject<ClientInfo>(result);

                    if (clientInfo != null)
                        record.email = clientInfo.email;
                }
            }

            return lstClientDetails;
        }
    }
user1263981
  • 2,953
  • 8
  • 57
  • 98
  • 2
    Better how? If I'm not mistaken, you're certainly misusing `GetAsync()` by directly accessing `.Result` on it – no need to use async functions at all in that case... – AKX Feb 22 '22 at 14:03
  • well, depending on some aspects like rate limiting of the service, or the service being able to handle multiple parallel requests, you could try parallelize it by using Parallel.Foreach and adapting some code parts to that (cancel token, locking..). if you run into rate limiting problems, you will have to implement that, making your solution a little bit more complicated. also, you could check if its a default rest api, which maybe has the feature to populate a whole entityset instead of doing single requests for each record – Michael Schönbauer Feb 22 '22 at 14:11
  • You use parallel tasks that's calling endPoints, please take a look at this post : https://stackoverflow.com/questions/7320491/simplest-way-to-run-three-methods-in-parallel-in-c-sharp – Bouam Feb 22 '22 at 14:21
  • Read this - [YOU'RE USING HTTPCLIENT WRONG AND IT IS DESTABILIZING YOUR SOFTWARE](https://www.aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/) – phuzi Feb 22 '22 at 14:39
  • Don't use `using (var client = new HttpClient())`, [here is why](https://www.aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/). Network calls are expensive, so try making less calls and fetch/post/put more data in each call. Try making an API which accepts the list of `IDs` as input and returns the required data, rather than making separate API calls in a loop. – phougatv Feb 22 '22 at 15:29

2 Answers2

0

Maybe you can change your code to use async/await pattern

private async Task populateDetails(List<ClientInfo> lstClientDetails)
{
    using (var client = new HttpClient())
    {
        client.BaseAddress = EndpointAddress;
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        string Uri = "";
        ClientInfo clientInfo;

        foreach (var record in lstClientDetails)
        {
            Uri = string.Format("{0}", record.id);

            var postResponse = await client.GetAsync(Uri);

            if (postResponse.IsSuccessStatusCode)
            {
                string result = await postResponse.Content.ReadAsStringAsync();

                clientInfo = JsonConvert.DeserializeObject<ClientInfo>(result);

                if (clientInfo != null)
                    record.email = clientInfo.email;
            }
        }
    }
}

And as you can see it doesn't make senso to return the same List which is passed as a paramters: the code will change the underlyne objects

Marco Beninca
  • 605
  • 4
  • 15
0

Reference Microsoft Docs Parallel Library

sample code:


public class ParallelClient
{
    private async Task ParallelRequest(List<string> requests)
    {
        var responses = new ConcurrentBag<HttpResponseMessage>();
        using (var client = new HttpClient())
        {
            Parallel.ForEach(requests, new ParallelOptions { MaxDegreeOfParallelism = 10 }, async r =>
                {
                    var requestMessage = new HttpRequestMessage();
                    requestMessage.Method = HttpMethod.Post;
                    requestMessage.Content = new StringContent(r, Encoding.UTF8, "application/json");
                    var response = await client.SendAsync(requestMessage);
                    responses.Add(response);
                });
        }
    }
}
wenming
  • 46
  • 2