sanjihan
sanjihan

Reputation: 5994

calling GetAsync multiple times only executes one time

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

Answers (3)

usefulBee
usefulBee

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

derpirscher
derpirscher

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

Federico Alterio
Federico Alterio

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

Related Questions