Multiple Requests Using Task.WhenAll() - c#

I am trying to stress test my WebApi that is uploaded onto Azure. Specifically this test is for logging into an app. I decided to make a mock client using c# and create a list of Tasks, each of which will send the same request to my WebApi. My problem is that it throws an exception after using more than 300 tasks.
The Exception: "Thread has been Cancelled"
Inner exception: "Object reference not set to an instance of an object."
Code where exception occurs: await (Task.WhenAll(tasks));
Am I doing something wrong in my test code? If so, what? And how to I correct the error? Thanks!
Notes:
-I have tried running the test code against the API locally
-The API code is surrounded by a try catch block and when running the test code against it, it did not hit my breakpoint set in the catch block and an exception was still thrown in the test code.
-Since this is a project at work, I have replaced real log in credentials and the URL to the API with stand-ins
below is my test code
public static async Task<decimal> LoginTestParallel3Async(){
Stopwatch timer = new Stopwatch();
var tasks = new List<Task>();
LoginRequestModel request = new LoginRequestModel();
int numOfRequests = 500;
decimal totalTimeForTasks = 0;
string jsonObject = "";
request.UserName = "User";
request.Password = "Password";
request.UserId = 0;
jsonObject = Newtonsoft.Json.JsonConvert.SerializeObject(request);
try
{
using (var client = new HttpClient())
{
for (int i = 0; i < numOfRequests; i++)
{
//tasks.Add(client.PostAsync("URLForAzure", new StringContent(jsonObject, Encoding.UTF8, "application/json")));
tasks.Add(client.PostAsync("URLForLocal", new StringContent(jsonObject, Encoding.UTF8, "application/json")));
}
timer.Start();
await (Task.WhenAll(tasks));
timer.Stop();
totalTimeForTasks = timer.ElapsedMilliseconds;
Console.WriteLine("total time for request: " + totalTimeForTasks + " milliseconds");
Console.ReadLine();
}
}
catch (Exception e)
{
Console.WriteLine(e.Message.ToString());
return totalTimeForTasks;
}
return totalTimeForTasks;
}

According to the documentation the value of MaxConnectionsPerServer property from HttpClient is 256 by default. So in order to achieve what you need, you have to change this value to a larger number.
https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclienthandler.maxconnectionsperserver?view=netcore-2.0#System_Net_Http_HttpClientHandler_MaxConnectionsPerServer
ex.
var client = new HttpClient(new HttpClientHandler { MaxConnectionsPerServer = 1000 });

Related

PostAsync call vanishes and web page becomes available again

I have a web page that I'm trying to call a web service and I'm having it skip out of the process when called.
Here's what I'm referring to...
When I call this method after the customer enters in their check information:
public CheckInfo SubmitCheck(CheckInfo checkInfo)
{
try
{
var check = new Check();
check.account_number = checkInfo.CheckAccountNumber;
check.transit_number = checkInfo.CheckRoutingNumber;
check.amount = checkInfo.Amount.ToString();
check.check_number = checkInfo.CheckNumber;
check.bill_to_city = checkInfo.City;
check.bill_to_country = "US";
check.bill_to_postal_code = checkInfo.Zip;
check.bill_to_street = checkInfo.Street;
check.bill_to_state = checkInfo.State;
check.name_on_check = checkInfo.NameOnCheck;
check.transaction_type = "sale";
check.account_type = checkInfo.AccountType;
check.check_type = checkInfo.CheckType;
var ent = new SuburbanPortalEntities();
var gatewaySettings = (from x in ent.GatewayUsers
where x.TokenId == CurrentCustomerSession.Current.TokenId &&
x.Gateway.Name == "DirectAch2"
select x).FirstOrDefault();
var credentials = new Authentication();
credentials.password = gatewaySettings.Password;
credentials.username = gatewaySettings.UserName;
var response = Process.SubmitCheck(credentials, check).Result;
The public class that calls the private class:
public static async Task<Response> SubmitCheck(Authentication authentication, Check check)
{
return await Submit(authentication, check, PaymentTypes.Check);
}
The SubmitCheck Method:
private static async Task<Response> Submit(Authentication authentication, Object payment, PaymentTypes paymentType)
{
var resp = new Response();
try
{
var client = new HttpClient();
var bodyjson = JsonConvert.SerializeObject(authentication);
var bodycontent = new StringContent(bodyjson, Encoding.UTF8, "application/json");
var authenticationPost =
await client.PostAsync("https://someplace.com/api/v2/Identity", bodycontent);
var bodyResponseJson = await authenticationPost.Content.ReadAsStringAsync();
When I get to this line, it just returns out of the method and it doesn't continue on with anything, it's like I never executed this method.
var authenticationPost =
await client.PostAsync("https://someplace.com/api/v2/Identity", bodycontent);
No other code is executed after this line. It just stops and the web page becomes available again. I have the method wrapped in a try catch but the catch isn't.. catching anything.
I'm at a loss at this poing, any suggestions?
EDIT#1
I wrapped the line in a try catch as suggested.
try
{
authenticationPost =
await client.PostAsync("https://someplace.com/api/v2/Identity", bodycontent);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
It's stepping out of the try/catch and never executing any more code after that. No exception is caught, nothing, it just runs the line and leaves the method.
Here's your problem:
var response = Process.SubmitCheck(credentials, check).Result;
Don't block on async code, as I describe on my blog. This is a common mistake for those new to async/await. Instead of Result, use await:
public async Task<CheckInfo> SubmitCheck(CheckInfo checkInfo)
{
...
var response = await Process.SubmitCheck(credentials, check);
Note that you'd then need to await the call to SubmitCheck, and so on. It's async all the way.
Side note: I recommend using the standard pattern of *Async suffixes on your method names; it makes it clearer in the code that their return values need to be awaited:
public async Task<CheckInfo> SubmitCheckAsync(CheckInfo checkInfo)
{
...
var response = await Process.SubmitCheckAsync(credentials, check);

RestSharp v107 not returning data

I’ve used RestSharp 106 in the past but now I’m trying to get a new project up and running with v107. I did a simple test below but I can’t get it to return any data so I must be missing something that I’m not understanding. I’ve put a breakpoint at the top of the method and can follow it all the way down until it makes the async call and then the app just quits. I see the initial logging but again nothing after the async call. I would have thought I would see some logging about the list count or even the “Application END” piece. Anyone have any ideas on what I’m doing wrong? I’ve kept but commented out some of the different things I’ve tried.
Link to the documentation I’m looking at.
https://restsharp.dev/intro.html#introduction
public async void Run()
{
_log.LogInformation("Application START");
try
{
var listPPC = new List<PriorPeriodCorrection>();
listPPC = await CallApi();
}
catch (Exception ex)
{
_log.LogError("Error: {0} | {1} | {2}", ex.Message, ex.StackTrace, ex.InnerException);
}
_log.LogInformation("Application END");
}
public async Task<List<PriorPeriodCorrection>> CallApi()
{
var listPPC = new List<PriorPeriodCorrection>();
var apiURL = "https://example.com";
var apiEndpoint = "api/payroll/getpriorpaycorrectiondata/from/2021-12-01/to/2021-12-07";
var proxyAddress = "http://example.com:9400";
var apiUsername = "someusername";
var apiPassword = "4PsaI69#tuv";
var options = new RestClientOptions(apiURL)
{
ThrowOnAnyError = true,
Timeout = 1000,
Proxy = new WebProxy(proxyAddress)
};
var client = new RestClient(options);
client.Authenticator = new HttpBasicAuthenticator(apiUsername, apiPassword);
var request = new RestRequest(apiEndpoint);
try
{
listPPC = await client.GetAsync<List<PriorPeriodCorrection>>(request);
//var response = await client.GetAsync<PriorPeriodCorrection>(request);
//var response = await client.GetAsync<List<PriorPeriodCorrection>>(request);
//var response = await client.GetAsync(request);
//if (!string.IsNullOrWhiteSpace(response.Content))
//{
// listPPC = JsonConvert.DeserializeObject<List<PriorPeriodCorrection>>(response.Content);
//}
//else
// _log.LogInformation("Response Content is Blank or NULL.");
}
catch (Exception ex)
{
_log.LogError("Error: {0} | {1} | {2}", ex.Message, ex.StackTrace, ex.InnerException);
}
_log.LogInformation("Response count: {0}", listPPC.Count);
return listPPC;
}

Cancel exception in code on http-request when server response 200

In my Xamarin.iOS app project I have a critical for me error. When I send request by http at first I get cancel exception and only at second time I have success result. In server access logs I see two success response, and my PHP script run twice too, and in my MySQL base there are 2 INSERT queries from php.
Its critical error for me and have try:
- change server,
- update my Mac OS(to 10.15.4),
- my iPhone (from 13.1.* to 13.4, by the way, in Mysql base I see users with the same problem with older versions of iOS)
- update Xcode (11.4)
- update Visual Studio (8.5) and Xamarin
- update System.Net.Http (4.3.4)
- try to set CancellationToken and newClient.Timeout, but it doesn't change something
In code I have additional second try to connect if it cancel. If I remove additional connect I will have just cancellation exception.
Code:
private async Task<string> PostAndHandleHttpRequestAsync(Dictionary<string, string> content)
{
var cancellationTokenSource = new CancellationTokenSource();
cancellationTokenSource.CancelAfter(100000 );
CancellationToken token = cancellationTokenSource.Token;
var newClient = new HttpClient();
//client.Timeout = new TimeSpan(0, 1, 0);
newClient.Timeout = TimeSpan.FromSeconds(200); // this is double the default
var contentSerialize = JsonConvert.SerializeObject(content);
try
{
var postAsyncResult = await newClient.PostAsync(GlobalSettings.urlToPHP, new StringContent(contentSerialize), token);
var responseBody = await postAsyncResult.Content.ReadAsStringAsync();
return responseBody;
}
catch (OperationCanceledException c)
{
//additional second try
if (cancellationCounter == 0 )
{
Console.WriteLine("second");
cancellationCounter = 1;
var postAsyncResult = await newClient.PostAsync(GlobalSettings.urlToPHP, new StringContent(contentSerialize), token);
Console.WriteLine("secondrio " + postAsyncResult.ToString());
var responseBody = await postAsyncResult.Content.ReadAsStringAsync();
return responseBody;
}
else
{
cancellationCounter = 0;
return "Cancel";
}
Console.WriteLine("cancel exception " + c.ToString() + c.Message);
return "Cancel";
}
catch (Exception e)
{
Console.WriteLine("Error PostAndHandleHttpRequestAsync " + e.Message);
return "Error";
}
}
Please help😒
Logs on server looks like this:
[31/Mar/2020:14:48:21 +0300] "POST /CPMP-PROD4-10.php HTTP/1.0" 200 116 "-" "CocktailParty/4 CFNetwork/1125.2 Darwin/19.4.0"
[31/Mar/2020:14:48:21 +0300] "POST /CPMP-PROD4-10.php HTTP/1.0" 200 116 "-" "CocktailParty/4 CFNetwork/1125.2 Darwin/19.4.0"
[31/Mar/2020:14:48:21 +0300] "POST /CPMP-PROD4-10.php HTTP/2.0" 200 116 "-" "CocktailParty/4 CFNetwork/1125.2 Darwin/19.4.0"
[31/Mar/2020:14:48:21 +0300] "POST /CPMP-PROD4-10.php HTTP/2.0" 200 116 "-" "CocktailParty/4 CFNetwork/1125.2 Darwin/19.4.0"

Using GRPC only connecting to dialog flow StreamingDetectIntent, stuck at await responseStream.MoveNext

I'm trying to use DialogFlow API v2 with Unity.
Since there's no official SDK for Unity yet I used the Grpc beta unity SDK and the generated C# code I created with Protobuf and protoc from Grpc tools
The Grpc beta unity sdk is hidden in this link.
https://packages.grpc.io/ just click a build ID and you will find a built unity package.
I imported Google.Apis.Auth.OAuth2 and Grpc.Auth which weren't included in the official Grpc unity beta sdk.
Then I wrote this code which seems to work fine except that await responseStream.MoveNext() is stuck.
I believe the main reason is I'm not sure where to set the path to the end point which is '/v2/projects/project-id/agent/intents'
GoogleCredential credential = GoogleCredential.FromJson(privateKey);
Grpc.Core.Channel channel = new Grpc.Core.Channel("dialogflow.googleapis.com", credential.ToChannelCredentials());
var client = new SessionsClient(channel);
CallOptions options = new CallOptions();
var duplexStream = client.StreamingDetectIntent();
var responseHandlerTask = System.Threading.Tasks.Task.Run(async () =>
{
IAsyncEnumerator<StreamingDetectIntentResponse> responseStream = duplexStream.ResponseStream;
while (await responseStream.MoveNext())//stuck here
{
StreamingDetectIntentResponse response = responseStream.Current;
}
// The response stream has completed
});
// Send requests to the server
bool done = false;
while (!done)
{
// Initialize a request
var queryInput = new QueryInput();
queryInput.AudioConfig = new InputAudioConfig();
queryInput.AudioConfig.LanguageCode = "ja";
queryInput.AudioConfig.SampleRateHertz = 141000;
queryInput.AudioConfig.AudioEncoding = AudioEncoding.Linear16;
StreamingDetectIntentRequest request = new StreamingDetectIntentRequest
{
Session = "",
QueryInput = queryInput,
};
var bytes = File.ReadAllBytes("test.wav");
request.InputAudio = Google.Protobuf.ByteString.CopyFrom(bytes);
try
{
await duplexStream.RequestStream.WriteAsync(request);
}
catch (System.Exception e)
{
context.Post(state =>
{
Debug.LogErrorFormat("{0}\n{1}\n{2}\n{3}", e.Message, e.HelpLink, e.Source, e.StackTrace);
}, null);
}
done = true;
}
await duplexStream.RequestStream.CompleteAsync();
await responseHandlerTask;
Thanks for advance.
I didn't add correction session to the request. The following fixed it.
StreamingDetectIntentRequest request = new StreamingDetectIntentRequest
{
Session = "projects/project-id/agent/sessions/sessionid",
QueryInput = queryInput,
};

Error reusing some async json method on windows phone

EDIT 1: I added below the code who calls and uses the second method, and the error and data I recive
First of all sorry if my English isn't good enough, and sorry if there is another thread with the solution. I haven't found it.
Ok, I'm making a windows phone 8 app that uses a lot of info from a web service. The app makes different Json Post and uses the info. I maked a method for Posting that WORKS:
public static async void checkdeviceid()
{
//Where we are posting to:
Uri theUri = new Uri("urlofexample");
//Create an Http client
HttpClient aClient = new HttpClient();
//Class that will be serialized into Json
objetoslistas.checkdeviceidinput paquete = new objetoslistas.checkdeviceidinput();
//Set some values
paquete.Text = "deviceID";
paquete.Text2 = App.device_id;
//serialize data
var serializado = JsonConvert.SerializeObject(paquete);
//Post the data
HttpResponseMessage aResponse = await aClient.PostAsync(theUri, new StringContent(JsonConvert.SerializeObject(paquete), Encoding.UTF8, "application/json"));
if (aResponse.IsSuccessStatusCode)
{
string res = await aResponse.Content.ReadAsStringAsync();
var respuestaperfil = JsonConvert.DeserializeObject<objetoslistas.checkdeviceidoutput>(res.ToString());
//Do something with the data
}
else
{
// show the response status code
String failureMsg = "HTTP Status: " + aResponse.StatusCode.ToString() + " - Reason: " + aResponse.ReasonPhrase;
}
}
This code its actually working, but the fact it's that my app will have maybe 30 or 40 diferent POST, so I tried to make a reusable method like this:
public static async Task<string> jsonPOST(Uri theUri, object paquete)
{
//Create an Http client and set the headers we want
HttpClient aClient = new HttpClient();
//serialize data
var serializado = JsonConvert.SerializeObject(paquete);
//Post the data
HttpResponseMessage aResponse = await aClient.PostAsync(theUri, new StringContent(JsonConvert.SerializeObject(paquete), Encoding.UTF8, "application/json"));
if (aResponse.IsSuccessStatusCode)
{
string res = await aResponse.Content.ReadAsStringAsync();
return res;
}
else
{
// show the response status code
String failureMsg = "HTTP Status: " + aResponse.StatusCode.ToString() + " - Reason: " + aResponse.ReasonPhrase;
return failureMsg;
}
}
This code gives me problems in the main, were it's called. As I can understand, the problem is that, as the method calls some await process, the rest of the code continues with the execution without expect for the await result...
The code in Main is:
objetoslistas.checkdeviceidinput paquete = new objetoslistas.checkdeviceidinput();
paquete.Text = "deviceID";
paquete.Text2 = App.device_id;
Uri url = new Uri("urlofhteservice");
Task<string> recibo = metodosJson.jsonPOST(url, paquete);
var respuestaperfil = JsonConvert.DeserializeObject<objetoslistas.checkdeviceidoutput>(recibo.ToString);
if (respuestaperfil.Text2 == null)
{
IsolatedStorageSettings.ApplicationSettings["DeviceRegistered"] = true;
}
else
{
IsolatedStorageSettings.ApplicationSettings["DeviceRegistered"] = false;
}
And I recive this error (translated from google translator, sorry)
There was an exception of type 'Newtonsoft.Json.JsonReaderException' in Newtonsoft.Json.DLL but not controlled in the user code
The data I have in "recibo" is
recibo Id = 1, Status = WaitingForActivation, Method = "{null}", Result = "{Not yet computed}" System.Threading.Tasks.Task<string>
So as I understand the await method is still waiting.
Was I clear?
Thanks

Categories