0

I've got a .NET Standard 2.0 library that's used by a variety of projects (.NET Framework, .NET Core, UWP, Xamarin, etc.). It's basically a data client that projects can call to get data from web service API methods. I'm trying to figure out how to improve performance when calls to a method happen in parallel. Example web service calling code for a POST is below. Normally all methods would use _client but this takes 42 seconds to complete 50 parallel calls. If I instantiate RestClient for every call (commented line in code) and use that for the await, 50 parallel calls take 10 seconds to complete. However the RestSharp Next docs say not to do this as the connection pool could become exhausted.

The performance hit may have to do with the ServicePointManager.DefaultConnectionLimit of 2 as I can sort of see calls coming in twos to the web service if the static _client is used. Digging around, I see that ServicePointManager.DefaultConnectionLimit needs to be set before the RestClient is initiated but I'm not sure how to do that in a .NET Standard library. Basic question: Can I get the 50 calls in 10 seconds performance without instantiating a client for every call? If so, how? Note this is a test scenario. In prod, I expect to have 200-300 parallel calls.

using System; 
using System.Net;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using RestSharp;

namespace DataClient.Helpers
{
    public static class ApiHelper
    {
        static string baseurl = "xxxxx";
        static RestClient _client = new RestClient(baseurl);

        public static async Task<RestResponse> PostResultAsync(string endpoint, string data, bool useApikey)
        {
            System.Net.ServicePointManager.DefaultConnectionLimit = 50;
            //RestClient client = new RestClient(baseurl);
            RestRequest request = new RestRequest(endpoint, Method.Post);
            request.AddStringBody(data, DataFormat.Json);
            request.AddHeader("Authorization", string.Format("Bearer {0}", Settings.AccessToken));

            if (useApikey)
            {
                request.AddHeader("apikey", "xxxxx");
            }

            try
            {
                var response = await _client.PostAsync(request);
                return response;
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }

        }
    }
}
NeilN
  • 29
  • 5
  • From their website: _"If you use a dependency-injection container, register your API client as a singleton"_ - Do you use DI? – Fildor May 17 '22 at 17:02
  • 1
    Well, In C# starting from Net Standard you can just use plain HttpClient and IHttpClientFactory in IoC containers. It has all necessary serialize/deserialize functionality as well as header settings, so RestSharp actually obsolete right now. About concurrency great article is here - https://makolyte.com/csharp-how-to-make-concurrent-requests-with-httpclient/ – eocron May 17 '22 at 17:26
  • @Fildor We do not. – NeilN May 17 '22 at 18:07
  • You should be injecting IHttpClientFactory into your services. https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-6.0 – Train May 17 '22 at 18:15
  • @eocron Really interesting article but that means refactoring all the Restsharp dependent code in all the methods that call the base GET and POST methods. – NeilN May 17 '22 at 18:19
  • Yeah, but you should weight pros/cons yourself. For me it seems pretty easy to refactor (regex replace on project most of the time). – eocron May 17 '22 at 18:22

0 Answers0