web api get request (httpclient call) after await keyword is executed in dotnet core

Revathi Neminathan 21 Reputation points
2022-08-12T11:02:53.007+00:00

I would like to do some operation which doesn't depend on API response and at the same time I want API to finish its process.
But in my case, API doesn't receive request when postasync is executed.
Instead, Web api receive request after await weatherForeCastdata.

Can anyone help me ?

public async Task<IEnumerable<WeatherForecast>> Get()  
            {  
                var rng = new Random();  
                 var weatherForeCastdata = new HttpClientCall<WeatherForecast>(_configuration).PostRequest(_configuration["Services:Payperiod"],new WeatherForecast());  
                Console.WriteLine("apiinvoked");  
                var data = await weatherForeCastdata;  
                //var data1 = await data.Content.ReadAsStringAsync();  
                return JsonConvert.DeserializeObject<IEnumerable<WeatherForecast>>(data);  
                  
            }  
      
    public class HttpClientCall<T> where T : class  
        {  
            HttpClientHandler httpClientHandler = new HttpClientHandler();  
            private readonly IConfiguration _configuration;  
            internal HttpClientCall(IConfiguration configuration)  
            {  
                httpClientHandler = new HttpClientHandler();  
                httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, sslPolicyErrors) =>  
                   {  
                       if (sslPolicyErrors == SslPolicyErrors.None)  
                       {  
                           return true;   //Is valid  
                       }  
                       return true;  
                   };  
                   _configuration = configuration;  
            }  
      
             
             
            public async Task<string> PostRequest(string apiUrl, T postObject)  
            {  
                using (var client = new HttpClient(httpClientHandler))  
                {  
                    client.DefaultRequestHeaders.Add("ClientId", _configuration["header"]);  
                      Console.WriteLine(apiUrl);  
                    var response = client.PostAsync(apiUrl, postObject, new JsonMediaTypeFormatter());  
      
                     var response1=await response;  
                    return await response1.Content.ReadAsStringAsync();  
                }  
            }  
    }
ASP.NET Core
ASP.NET Core
A set of technologies in the .NET Framework for building web applications and XML web services.
4,400 questions
0 comments No comments
{count} votes

Accepted answer
  1. AgaveJoe 27,696 Reputation points
    2022-08-12T15:50:48.687+00:00

    As far as I can tell the code execution is exactly as written.

    Here's a more straight forward example of an async/await pattern.

    HttpClient client = new HttpClient();  
    Task task = ExecuteHttpRequestAsync();  
      
    Console.WriteLine($"Doing work while waiting for a response");  
      
    await task;  
      
    Console.WriteLine("Doing work after receiving the response");  
      
      
    async Task ExecuteHttpRequestAsync()  
    {  
        Console.WriteLine($"ExecuteHttpRequest Start {DateTime.Now.ToString("hh:mm:ss")}");  
        Console.WriteLine();  
        client.BaseAddress = new Uri("https://localhost:7134");  
      
        HttpResponseMessage response = await client.GetAsync("WeatherForecast");  
        string json = await response.Content.ReadAsStringAsync();  
        //Console.WriteLine(json);  
        Console.WriteLine();  
        Console.WriteLine($"ExecuteHttpRequest End {DateTime.Now.ToString("hh:mm:ss")}");  
    }  
    

    The Web API action has a 5 second delay.

            [HttpGet(Name = "GetWeatherForecast")]  
            public async Task<IEnumerable<WeatherForecast>> GetAsync()  
            {  
                await Task.Delay(1000 * 5);  
                return Enumerable.Range(1, 5).Select(index => new WeatherForecast  
                {  
                    Date = DateTime.Now.AddDays(index),  
                    TemperatureC = Random.Shared.Next(-20, 55),  
                    Summary = Summaries[Random.Shared.Next(Summaries.Length)]  
                })  
                .ToArray();  
            }  
    

    Sample results

    ExecuteHttpRequest Start 11:48:51  
      
    Doing work while waiting for a response  
      
    ExecuteHttpRequest End 11:48:56  
    Doing work after receiving the response  
    

    Reference documentation
    Asynchronous programming with async and await


4 additional answers

Sort by: Most helpful
  1. Bruce (SqlWork.com) 61,731 Reputation points
    2022-08-12T15:53:20.933+00:00

    Pretty simple

    var rq = PostRequest(url, data);  
      
    // do some work  
      
    var value = await rq;  
      
    
    0 comments No comments

  2. Revathi Neminathan 21 Reputation points
    2022-08-16T12:19:52.843+00:00
    @agavejoe  
    Is your web api received request after client.GetAsync("WeatherForecast") method?  
    In my case , web api received request after await task.  
    you can check by adding console.WriteLine in your web api.  
    Here is my program with log  
    **Caller :**  
     [HttpGet]  
            public async Task<IEnumerable<WeatherForecast>> Get()  
            {  
                var rng = new Random();                
                Console.WriteLine("api invoked"+DateTime.Now.ToString("hh:mm:ss.fff"));  
                var  weatherForeCastdata = GetData();  
                 Console.WriteLine("Doing work while waiting for response"+DateTime.Now.ToString("hh:mm:ss.fff"));  
                //await Task.Delay(5000);  
                var data = await weatherForeCastdata;  
                Console.WriteLine("Doing work after response"+DateTime.Now.ToString("hh:mm:ss.fff"));             
                return JsonConvert.DeserializeObject<IEnumerable<WeatherForecast>>(data);  
                  
            }  
            public Task<string> GetData()  
            {  
                   return  new HttpClientCall<WeatherForecast>(_configuration).PostRequest(_configuration["Services:Payperiod"],new WeatherForecast());    
            }  
      
    **Receiver :**  
      
    public async Task<IEnumerable<WeatherForecast>> Post(WeatherForecast weatherforcast)  
            {  
                Console.WriteLine("API request "+DateTime.Now.ToString("hh:mm:ss.fff"));  
                await Task.Delay(5000);  
                var rng = new Random();  
                return Enumerable.Range(1, 5).Select(index => new WeatherForecast  
                {  
                    Date = DateTime.Now.AddDays(index),  
                    TemperatureC = rng.Next(-20, 55),  
                    Summary = Summaries[rng.Next(Summaries.Length)]  
                })  
                .ToArray();  
            }  
    **logs of caller**  
      
    api invoked05:46:25.286  
    Doing work while waiting for response05:46:25.312  
    Doing work after response05:46:30.562  
      
    **logs of receiver**  
    API request 05:46:25.502  
      
    you can check API request time in receiver. It should be less than Doing work while waiting for response  time but in this case  it is greater.  
    

    So API receive request after await statement not after postasync method


  3. Bruce (SqlWork.com) 61,731 Reputation points
    2022-08-17T16:05:02.45+00:00

    no. when you call an async routine, it is sync until it creates and returns a Task. in you api:

    // still on the caller thread    
    Console.WriteLine("API request "+DateTime.Now.ToString("hh:mm:ss.fff"));  
      
    // create new Task and thread and return control to caller  
    await Task.Delay(5000);  
      
    

    this is why the api print happens before the print after the api call. for example:

    // this is basically a sync method which will block the caller until it returns  
      
    Task<bool> foo()   
    {  
        for (I = 0; I < 100000; ++i)  
              ;  
        Console.WriteLine("done");  
        return Task.FromResult(true);  
    }  
      
      
    

  4. AgaveJoe 27,696 Reputation points
    2022-08-18T18:45:22.15+00:00

    You misunderstand. Your code is functioning as expected. The problem is your code is not as resource efficient as possible.

    public async Task<string> GetData()  
    {  
        var client =  new HttpClientCall<WeatherForecast>(_configuration)      
        await client.PostRequest(_configuration["Services:Payperiod"],new WeatherForecast());    
    }  
    

    The async yields control to the caller which allows the caller to do other tasks while the GetData() finishes its processing. When GetData() is done it updates the Task<string> object it passed to the caller. Your code without the async causes the caller to go idle while it waits for GetData() to finish. That's what blocking means. It does not mean the API call is blocked.

    Another way to say this is if you write proper async/await code your server can handle more requests.

    The link in my prior post explains the mechanics.

    0 comments No comments