C
C#4w ago
surwren

Making Concurrent API calls Asynchronously (Is this Correct?)

Apologies for the long code, need to split it up into 2 posts because it's really long:
async Task SendUserInfoRequestAsync() {
if (string.IsNullOrEmpty(sessionCache.loginToken)) {
Debug.LogError("No login token found.....");
return;
}
Uri userInfoUri = new Uri(new Uri(baseUrl), userInfoRoute);
Uri getUserInfoUri = new Uri(new Uri(baseUrl), getUserInfoRoute);

using (HttpClient client = new HttpClient()) {
try {
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", sessionCache.loginToken);

Task<HttpResponseMessage> task1 = client.PostAsync(userInfoUri, null);
Task<HttpResponseMessage> task2 = client.PostAsync(getUserInfoUri, null);

HttpResponseMessage response1 = await task1;
HttpResponseMessage response2 = await task2;

if (!response1.IsSuccessStatusCode || !response2.IsSuccessStatusCode) {
string errorMessage = "Request from SendUserInfoRequestAsync() failed. ";
if (!response1.IsSuccessStatusCode) {
lastHttpResponseError = response1;
errorMessage += $"First request failed";
}
if (!response2.IsSuccessStatusCode) {
lastHttpResponseError = response2;
errorMessage += $"Second request failed.";
}
Debug.LogError(errorMessage);
}
async Task SendUserInfoRequestAsync() {
if (string.IsNullOrEmpty(sessionCache.loginToken)) {
Debug.LogError("No login token found.....");
return;
}
Uri userInfoUri = new Uri(new Uri(baseUrl), userInfoRoute);
Uri getUserInfoUri = new Uri(new Uri(baseUrl), getUserInfoRoute);

using (HttpClient client = new HttpClient()) {
try {
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", sessionCache.loginToken);

Task<HttpResponseMessage> task1 = client.PostAsync(userInfoUri, null);
Task<HttpResponseMessage> task2 = client.PostAsync(getUserInfoUri, null);

HttpResponseMessage response1 = await task1;
HttpResponseMessage response2 = await task2;

if (!response1.IsSuccessStatusCode || !response2.IsSuccessStatusCode) {
string errorMessage = "Request from SendUserInfoRequestAsync() failed. ";
if (!response1.IsSuccessStatusCode) {
lastHttpResponseError = response1;
errorMessage += $"First request failed";
}
if (!response2.IsSuccessStatusCode) {
lastHttpResponseError = response2;
errorMessage += $"Second request failed.";
}
Debug.LogError(errorMessage);
}
6 Replies
surwren
surwrenOP4w ago
var responseJsonList = new List<JObject>
{
await ProcessServerResponse(response1, userInfoUri),
await ProcessServerResponse(response2, getUserInfoUri)
};
if (int.TryParse(responseJsonList[0]["code"]?.ToString(), out int responseCodeInternal1) && responseCodeInternal1 == 200 ||
int.TryParse(responseJsonList[1]["code"]?.ToString(), out int responseCodeInternal2) && responseCodeInternal2 == 200) {
await UpdateLocalData(responseJsonList);
}
else {
if (responseCodeInternal1 != 200) {
lastHttpResponseError = response1;
}
else if (responseCodeInternal2 != 200) {
lastHttpResponseError = response2;
}
Debug.LogError("Unable to retrieve info.");
}
}
catch (Exception ex) {
Debug.LogError("Exception...");
}
}
}
var responseJsonList = new List<JObject>
{
await ProcessServerResponse(response1, userInfoUri),
await ProcessServerResponse(response2, getUserInfoUri)
};
if (int.TryParse(responseJsonList[0]["code"]?.ToString(), out int responseCodeInternal1) && responseCodeInternal1 == 200 ||
int.TryParse(responseJsonList[1]["code"]?.ToString(), out int responseCodeInternal2) && responseCodeInternal2 == 200) {
await UpdateLocalData(responseJsonList);
}
else {
if (responseCodeInternal1 != 200) {
lastHttpResponseError = response1;
}
else if (responseCodeInternal2 != 200) {
lastHttpResponseError = response2;
}
Debug.LogError("Unable to retrieve info.");
}
}
catch (Exception ex) {
Debug.LogError("Exception...");
}
}
}
exixt
exixt4w ago
make the calls separate. one method should only be doing one thing you're introducing more complexity here
Omnissiah
Omnissiah4w ago
this is ok (although you could use var)
HttpResponseMessage response1 = await task1;
HttpResponseMessage response2 = await task2;
HttpResponseMessage response1 = await task1;
HttpResponseMessage response2 = await task2;
but then this calls are in sequence...
var responseJsonList = new List<JObject>
{
await ProcessServerResponse(response1, userInfoUri),
await ProcessServerResponse(response2, getUserInfoUri)
};
var responseJsonList = new List<JObject>
{
await ProcessServerResponse(response1, userInfoUri),
await ProcessServerResponse(response2, getUserInfoUri)
};
surwren
surwrenOP4w ago
What is the proper way to make them concurrent
Becquerel
Becquerel4w ago
your method is somewhat concurrent but it's not optimal instead you should be using Task.WhenAll var task1 = client.Foobar(); var task2 = client.Barfoo(); await Task.WhenAll(task1, task2); // Calling the .Result property is only safe after the Task has been awaited. Console.WriteLine("Results are: {task1.Result} and {task2.Result}"); this also signals your intent to other developers more clearly @surwren
Becquerel
Becquerel4w ago
unrelated to async, you should avoid creating new httpclient instances in using blocks, as this can lead to socket exhaustion. the better approach is to use a single longlived instance, or look into using IHttpClientFactory https://learn.microsoft.com/en-us/dotnet/fundamentals/networking/http/httpclient-guidelines
HttpClient guidelines for .NET - .NET
Learn about using HttpClient instances to send HTTP requests and how you can manage clients using IHttpClientFactory in your .NET apps.
Want results from more Discord servers?
Add your server