1

My code looks something like this:

private readonly HttpClient _httpClient;

public SomeConstructor(HttpClient httpClient){
     _httpClient = httpClient;
}

public void SomeMethod(string reqUrl, string payload){
     var result = GetResponseStringAsync(reqUrl, payload).GetAwaiter().GetResult();
     // do something with result
}

private async Task<string> GetResponseStringAsync(string reqUrl, string payload){
     using (var req = new HttpRequestMessage("POST", reqUrl)){
          using (var content = new StringContent(payload)){
               // Attach content headers here (specific for each request)

               req.Content = content;
               // Attach request headers here (specific for each request)
               // using req.Headers.TryAddWithoutValidation()

               using (var response = await _httpClient.SendAsync(req))
               {
                   return await response.Content.ReadAsStringAsync();
               }
          }
     }
}

I need to send API requests that have different, signed headers per request, otherwise I will get back 401 (Unauthorized). That said, when I send a single request, I always got 200, indicating that the authorization headers are sent correctly. However, if I send multiple requests at once (say with concurrency level set to 10), only 1 request got 200 back, whereas the other 9 got 401s. If I click on these 9 links individually, however, I got 200s for every single one of them, as expected.

It seems to me that somehow, there's a concurrency issue that results in the proper headers not being attached to their corresponding requests, even when I create a new HttpRequestMessage for each request. HttpClient and HttpRequestMessage both are supposedly thread-safe but could someone provide an explanation as to why I'm still getting weird results when sending multiple requests at once?

Add:

  1. I have something like this in my AppHost: Container.Register<ISomeConstructor>(x => new SomeConstructor(new HttpClient())); so I am sure I'm not accidentally modifying the client anywhere else
  2. Placing a lock around the HttpClient (just before the SendAsync call) makes it work and returns 200s 100% of the time, further convincing me that it's a concurrency issue
  3. I'm deploying and running on Mono 6.8.0.105 -- could this be a Mono issue? I couldn't find any issues/bug reports on this though
natasha
  • 263
  • 1
  • 9
  • Could you show an example of how you are adding specific request headers for each individual request? i.e. Maybe you are adding headers to the shared `HttpClient` instead of the `HttpRequestMessage`? – C. Augusto Proiete Feb 20 '20 at 03:05
  • when you `req.Content = content`, your `content` is already disposed – vasily.sib Feb 20 '20 at 03:23
  • @vasily.sib oops bad copy-paste, I updated the code. But no, it's not disposed until after the API call is made. – natasha Feb 20 '20 at 03:43
  • @CaioProiete sure, just updated the code too, but I was just using `req.Headers.TryAddWithoutValidation()`. The Authorization header I need to pass doesn't exactly conform to the standard format hence the without validation method. – natasha Feb 20 '20 at 03:45
  • Maybe check the lift cycle of the class if you are injecting, I would normally put this as a singleton. Not sure if your using .net core(so this might not help), but if so, its worth looking at. https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-3.1 You can actually add the headers in startup.cs and then this is used every time that instance of the client is called. Also its worth noting some of the behaviour or httpclient can be odd, so if you change some of its configuration in a method, it can actually reset headers etc. – Netferret Feb 20 '20 at 09:29

0 Answers0