Reputation: 5994
I'am trying to call GetAsync multiple times in a nonblocking async function. To my surprise only the fist call gets executed. All requests are to the same domain so I figured it makes sense to reuse HttpClient
. Why is only the first request executed and how should I rewrite the code?
private static HttpClient client = new HttpClient(new HttpClientHandler(){UseProxy = false});
private static async Task NonblockingGet(string destination){
client.Timeout = TimeSpan.FromSeconds(10);
var result = await client.GetAsync(destination);
// handle result
}
private static void CallMultipleTimes(){
NonblockingGet("domain1/url1"); // only this one is executed
NonblockingGet("domain1/url2");
NonblockingGet("domain1/url3");
}
//main
ManualResetEvent mre = new ManualResetEvent(false);
CallMultipleTimes();
mre.WaitOne();
Upvotes: 1
Views: 1076
Reputation: 9692
I came across a similar problem, and even though I could not figure out the exact underlaying root cause, I was finally able to overcome the issue, where only the first call to the api was successfully executing while every other call throwing 403 Forbidden
error, after implementing the following solution and switching from using:
private static readonly HttpClient client = new HttpClient();
To using:
private static IHttpClientFactory factory = new ServiceCollection()
.AddHttpClient()
.BuildServiceProvider()
.GetRequiredService<IHttpClientFactory>();
Upvotes: 0
Reputation: 17372
No, all three calls to NonblockingGet
are executed. But on the second call, you are trying to modify the client
(ie set the Timeout) after there was already a request started. That's not allowed and it throws a System.InvalidOperationException
exception (which is silently ignored)
This instance has already started one or more requests. Properties can only be modified before sending the first request.
Thus, of course, the second and the third client.GetAsync()
are not executed.
Move the client.Timeout = TimeSpan.FromSeconds(10);
to be the first statement in CallMultipleTimes()
(or somewhere else where it's only executed once before the very first request) and everything will work as expected (at least for this usecase).
private static async Task NonblockingGet(string destination){
// client.Timeout = TimeSpan.FromSeconds(10); // <--- remove it here
var result = await client.GetAsync(destination);
// handle result
}
private static void CallMultipleTimes(){
client.Timeout = TimeSpan.FromSeconds(10); // <--- add it here
NonblockingGet("domain1/url1"); // only this one is executed
NonblockingGet("domain1/url2");
NonblockingGet("domain1/url3");
}
Upvotes: 3
Reputation: 502
I'm not understanding why only the first call is executed (I tried the code myself and all of them are correctly called). However usually you don't want to mix Thread Waiting with async code. And you want all your async operation to be awaited and executed inside a Task (For correct exception handling).
That's my proposal
HttpClient client = new HttpClient(new HttpClientHandler() { UseProxy = false});
async Task NonblockingGet(string destination)
{
client.Timeout = TimeSpan.FromSeconds(10);
var result = await client.GetAsync(destination);
// handle result
}
async Task CallMultipleTimes() =>
await Task.WhenAll(NonblockingGet("domain1/url1"), NonblockingGet("domain1/url2"), NonblockingGet("domain1/url3"));
// Main
await CallMultipleTimes();
// If you are here all 3 operations requests are completed
Notes: If you are using .Net < 6.0 you have to change your Main function signature from static void to static async Task.
Upvotes: 0