Search code examples
c#.net-corehangfire

How to perform postasync operation inside a loop in C#


I have a hangfire job build in C# .netcore. This job is making postasync call inside a forloop. After first call to api, it is throwing below error.

This instance has already started one or more requests. Properties can only be modified before sending the first request

How to make post call synchronously in a loop effectively? Call needs to be synchronous.

class myclass
{

  public void process(){
  
   _httpClient = new HttpClient();
   
   foreach(var item in list){
   _httpClient.BaseAddress = baseUri;
            _httpClient.DefaultRequestHeaders.Clear();
            _httpClient.DefaultRequestHeaders.ConnectionClose = true
    var res=  _httpClient.PostAsync(url,body);
    var result= res.content.readasstringasync().Result;
    saveResultInDB(result);
   }
  }

Solution

  • HttpClient is thread-safe and meant to be reused. Modifying BaseAddress and DefaultRequestHeaders modifies the defaults used by all requests, including the current ones. Modifying these inside a loop only causes problems.

    HttpClient methods are asynchronous. Instead of blocking each one, it's far easier and cleaner to write a proper asynchronous method and then, if and only if there's a real need, call it in a blocking way.

    Assuming the base URL and headers don't change, the code could change to :

    
    HttpClient _httpClient;
    
    public MyClass()
    {
        _httpClient=new HttpClient();
        _httpClient.DefaultHeaders......;
    }
    
    public void Process()=>ProcessAsync().Wait();
    
    public async Task ProcessAsync(List<Item> items)
    { 
       foreach(var item in items)
       {    
            var absoluteUrl=CalculateUrl(item);
            var res=  await _httpClient.PostAsync(absoluteUrl,item.Body);
            var result= await res.Content.ReadAsStringAsync();
            saveResultInDB(result);
       }
    }