Home > Net >  ASP.NET Core synchronously wait for http request
ASP.NET Core synchronously wait for http request

Time:11-11

I have an external endpoint which I call to get some Json response. This endpoint will initiate a session to a POS device, so the device will show the request details and ask the customer to enter his credit card to complete the payment, then when the customer finishes; the POS will call the endpoint and it will return the result back to my application.

The problem here is that I need the operation to complete as described in this scenario (synchronously).

When I do the call to this endpoint from postman; it waits a lot of time (until the POS receives the request and customer do his entries then returns the results back to endpoint and endpoint returns the results back to Postman) ... this is all works fine.

The problem is when I do this from an ASP.NET Core app, the request is not waited for endpoint and the response is returned with null directly.

I need something to wait for it.

using (var client = new HttpClient())
{
        client.DefaultRequestHeaders.Add("x-API-Key", "ApiKey");
        client.DefaultRequestHeaders.Add("Connection", "keep-alive");
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

        var postTask = client.PostAsJsonAsync(new Uri("terminalEndpoint here"), dto);//dto is the request payload

        postTask.Wait();

        var result = postTask.Result;

        if (result.IsSuccessStatusCode)
        {
            //Should hang after this line to wait for POS
            var terminalPaymentResponseDto =  result.Content.ReadAsAsync<InitiateTerminalPaymentResponseDto>().Result;

            //Should hit this line after customer finishes with POS device
            return terminalPaymentResponseDto;
        }
    }

CodePudding user response:

Why not use the await like below? And make sure to change the function to async

var postTask = await client.PostAsJsonAsync(new Uri("terminalEndpoint here"), dto);

CodePudding user response:

First of all, there's no need to block. In fact, in an ASP.NET Core application you should avoid blocking as much as possible. Use async and await instead. This allows ASP.NET Core to use the freed threadpool thread for other work.

Second, HttpClient is thread-safe and meant to be reused. Creating a new one every time in a using block leaks sockets. You could use a static instance but a better solution is to use IHttpClientFactory as Make HTTP requests using IHttpClientFactory in ASP.NET Core shows, to both reuse and recycle HttpClient instances automatically.

Finally, there's no reason to add these headers on every call. The Content-Type is set by PostAsJsonAsync anyway. I also suspect the API key doesn't change when calling the same server either.

In your Startup.cs or Program.cs you can use AddHttpClient to configure the API Key :

builder.Services.AddHttpClient(client=>{
    client.DefaultRequestHeaders.Add("x-API-Key", "ApiKey");
});

After that you can inject IHttpClientFactory into your controllers or pages and call it asynchronously in asynchronous actions or handlers :

public class MyController:ControllerBase
{
    private readonly IHttpClientFactory _httpClientFactory;

    public MyController:ControllerBase(IHttpClientFactory httpClientFactory) =>
        _httpClientFactory = httpClientFactory;


    public async Task<InitiateTerminalPaymentResponseDto> PostAsync(MyDTO dto)
    {
        var client=_httpClientFactory.CreateClient();

        var uri=new Uri("terminalEndpoint here");
        var result = client.PostAsJsonAsync(uri, dto);payload

        if (result.IsSuccessStatusCode)
        {
            //Should hang after this line to wait for POS
            var paymentDto=  await result.Content.ReadAsAsync<InitiateTerminalPaymentResponseDto>();

            //Should hit this line after customer finishes with POS device
            return paymentDto;
        }      
        else {
            //Do whatever is needed in case of error
        }
    }
}

Using HttpClientFactory allows adding retry strategies using Polly eg, to recover from a temporary network disconnection.

  • Related