'ASP.NET Core 5.0 Web API deployed in App service call third party API fails intermittently and raise 500 (Internal Server Error)

ASP.Net Core Web API Call Thirds party API fails intermittently.

The following exception raises intermittently when load test with postman. "Call failed with status code 500 (Internal Server Error): POST https://sample.com/apiendpoint."

I tried the Named/Typed with HttpClient/IHttpClientFactory approach and the problem continues.

How to make sure it uses connection pooling and not create new on one. what is the right value for SetHandlerLifetime to keep the connection in the pool for future call to use.

    services.AddHttpClient<IRestService, RestServiceOne>()
    .SetHandlerLifetime(TimeSpan.FromMinutes(5))  //Set lifetime to five minutes
    .AddPolicyHandler(GetRetryPolicy());

The following code is in RestServiceOne.cs

   public class RestServiceOne : IRestService
    {
        private readonly IHttpClientFactory _httpClientFactory;
        public RestServiceOne(IHttpClientFactory httpClientFactory)
        {
            _httpClientFactory = httpClientFactory;
        }
        public async Task<HttpResponseMessage> GetDataAsync(string destinationUrl, string user,
            string password, string requestXml, string orderNumber, CancellationToken cancellationToken)
        {
            var endpoint = $"{destinationUrl}";
            var authToken = Encoding.ASCII.GetBytes($"{user}:{password}");
            var data = new StringContent(requestXml, Encoding.UTF8, "text/xml");
            var httpRequestMessage = new HttpRequestMessage(
                HttpMethod.Post,
                endpoint)
            {
                Headers =
            {
                { "Accept", "application/vnd.github.v3+json" },
                { "User-Agent", "HttpRequestsConsoleSample" }
            }
            };
            httpRequestMessage.Content = data;
            var httpClient = _httpClientFactory.CreateClient();

            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
                    Convert.ToBase64String(authToken));
            var httpResponseMessage = await httpClient.SendAsync(httpRequestMessage);
            return httpResponseMessage;

        }
    }

I also tried HttpClient injection given in Microsoft type example.

public class RestService 
{
    private readonly HttpClient _httpClient;
    public RestService(HttpClient httpClient)
    {
        _httpClient = httpClient;
        try
        {
            _httpClient.BaseAddress = new Uri("https://testxx.com/test");
            // GitHub API versioning
            _httpClient.DefaultRequestHeaders.Add("Accept",
                "application/vnd.github.v3+json");
            // GitHub requires a user-agent
            _httpClient.DefaultRequestHeaders.Add("User-Agent",
                "HttpClientFactory-Sample");
        }
        catch(Exception ex)
        {

        }
    }

    public async Task<HttpResponseMessage> GetDataAsync(string destinationUrl, string user,
        string password, string requestXml, string orderNumber, CancellationToken cancellationToken)
    {
        var endpoint = $"{destinationUrl}";
        var authToken = Encoding.ASCII.GetBytes($"{user}:{password}");
        _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
                Convert.ToBase64String(authToken));
        var data = new StringContent(requestXml, Encoding.UTF8, "text/xml");
        try
        {
            var response = await _httpClient.PostAsync(endpoint, data);
            return response;
        }
        catch(Exception ex)
        {
            throw;
        }
    }
}

I tried with Flurl directly in service layer

var endpoint = $"{destinationUrl}";
var authToken = Encoding.ASCII.GetBytes($"{user}:{password}");
var data = new StringContent(requestXml, Encoding.UTF8, "text/xml");
try
{

var response = await endpoint
    .WithHeader("Content-Type", "text/xml")
    .WithHeader("app-bu-id", "SANIDERMMEDICAL")
    .WithHeader("Authorization", new AuthenticationHeaderValue("Basic", Convert.ToBase64String(authToken)))
    .PostAsync(data);

The above all 3 approach failed.

what is right value for .SetHandlerLifetime() to keep the connection in the pool and avoid creating new.

I saw some other example using the following approach but how to use this with IHttpClientFactory / Flurl.

var socketsHandler = new SocketsHttpHandler
{
    PooledConnectionLifetime = TimeSpan.FromMinutes(10),
    PooledConnectionIdleTimeout = TimeSpan.FromMinutes(5),
    MaxConnectionsPerServer = 10
};

var client = new HttpClient(socketsHandler);

How can I ensure it use connection pooling and avoid the 500 error when calling 3rd party API from Azure.



Solution 1:[1]

I found solution when I use httpclient as given below.

    private static readonly HttpClient httpClient = new HttpClient(new SocketsHttpHandler
    {
        PooledConnectionLifetime = TimeSpan.FromSeconds(60),
        PooledConnectionIdleTimeout = TimeSpan.FromSeconds(20),
        MaxConnectionsPerServer = 10
    });

This article helped me

Tried couple of value for SocketsHttpHandler but finally choose this since no error.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 user3497702