System.Net.Http.HttpClient Timeout seems to be ignored - c#

I am using Xamarin.iOS Version: 8.10.5.26 (Indie Edition) and facing a very strange behaviour with timing out requests sent with HttpClient():
The following code tries to get a result from an url, and has 60 seconds timeout (1 minutes), but when the request is fired it is taking around 90 seconds for time out. When call is made, I manually turn off the network connectivity to check the time out. It is observed that it is taking more than 60 seconds.
CODE
public async Task<Dictionary<string,object>> GetPatientDataASync (string lUsername)
{
var lDict = new Dictionary<string,object> ();
try {
string lQuerystring = "{Email: '" + lUsername + "'}";
String lUrl = String.Format (Constants.mURLPatient + "?where={0}", JObject.Parse (lQuerystring));
var lClient = new HttpClient ();
lClient.BaseAddress = new Uri (lUrl);
lClient.DefaultRequestHeaders
.Accept
.Add (new MediaTypeWithQualityHeaderValue ("application/json"));
lClient.DefaultRequestHeaders.Add ("X-Parse-Application-Id", Constants.mKeyParseAppId);
lClient.DefaultRequestHeaders.Add ("X-Parse-REST-API-Key", Constants.mKeyRestAPIKey);
lClient.Timeout = new TimeSpan (0, 1, 0);
var request = new HttpRequestMessage ();
request.Method = HttpMethod.Get;
if (Utility.isNetworkConnected ()) {
bool responseStatus = false;
await lClient.SendAsync (request)
.ContinueWith (responseTask => {
if (responseTask != null) {
var response = responseTask.Result;
if (response != null) {
if (response.IsSuccessStatusCode) {
var responseContent = response.Content;
if (responseContent != null) {
string responseString = responseContent.ReadAsStringAsync ().Result;
if (!string.IsNullOrWhiteSpace (responseString)) {
JObject json = JObject.Parse (responseString);
if (json != null) {
if (json ["results"].Any ()) {
Patient user = Patient.Instance;
user.objectId = json.SelectToken (#"results[0].objectId").Value<string> ();
user.Email = json.SelectToken (#"results[0].Email").Value<string> ();
user.Name = json.SelectToken (#"results[0].Name").Value<string> ();
user.IsNotificationsEnabled = json.SelectToken (#"results[0].IsNotificationsEnabled").Value<string> ();
Application.Current.Properties ["IsNotificationsEnabled"] = json.SelectToken (#"results[0].IsNotificationsEnabled").Value<string> ();
if (json.SelectToken (#"results[0].DeviceToken") != null) {
var deviceToken = json.SelectToken (#"results[0].DeviceToken").Value<JArray> ();
if (deviceToken != null)
user.DeviceToken = deviceToken.ToObject < List<string>> ();
} else {
user.DeviceToken = new List<string> ();
}
var doctors = json.SelectToken (#"results[0].MyDoctors").Value<JArray> ();
user.AllergicTo = json.SelectToken (#"results[0].AllergicTo").Value<string> ();
user.ContactNo = json.SelectToken (#"results[0].ContactNo").Value<string> ();
user.BloodGroup = json.SelectToken (#"results[0].BloodGroup").Value<string> ();
user.MyDoctors = doctors != null ? doctors.ToObject<List<string>> () : new List<string> ();
responseStatus = true;
} else
responseStatus = false;
}
}
}
}
}
}
});
lDict.Add (SUCCESS_CODE, responseStatus);
return lDict;
} else {
lDict.Add (NO_INTERNET, Constants.mStringNoInternetMessage);
return lDict;
}
} catch (Exception e) {
Debug.WriteLine (e.Message + "\n " + e.StackTrace);
lDict.Add (EXCEPTION_OCCURED, e);
return lDict;
}
}
If there's some mistake in my code , please do let me know.
Also the same issues are reported here :-
First link
Second Link

This is a know bug which was opened, closed and re-opened several times over the years. It is already reported here and here.

There is work-around solution:
Define CancellationTokenSource and Set Token to http request;
Invoke cancel by timeout on CancellationTokenSource like this cts.CancelAfter(timeout);:
Don't forgot catch exception, like this.
try
{
}
catch(TaskCanceledException)
{
if(!cts.Token.IsCancellationRequested)
{// timeout
}
else
{//other reason
}
}

Related

C# Multiple Web Data/Stream Reader

I'm trying to learn programming by myself the best I can but, seems like my code isn't as productive as it can be. I'm trying to learn by doing things that I would use on a normal occasion and I can't figure out how to properly manage it, so any information would be greatly appreciated.
I'm working on a discord bot for personal use at the moment, it works fine, the loadout time is just terrible when it comes to this part of the command. Maybe cause I'm trying to have it open, read, and close multiple databases? Or is there another explanation or method to doing this that can make it load within a faster time?
string NormalExp = "0";
string IronExp = "0";
string HCExp = "0";
string UIMExp = "0";
//Normal Account
try
{
WebRequest NormalScore = WebRequest.Create("https://secure.runescape.com/m=hiscore_oldschool/index_lite.ws?player=" + player);
WebResponse NormalResponse = NormalScore.GetResponse();
using (Stream NormalDStream = NormalResponse.GetResponseStream())
{
StreamReader NormalReader = new StreamReader(NormalDStream);
string NormalResponseFromServer = NormalReader.ReadToEnd();
var _Score = NormalResponseFromServer.Split('\n');
var _Total = _Score[0];
var _TotalGet = _Total.Split(',');
var _TotalRank = _TotalGet[0];
var _TotalLevel = _TotalGet[1];
var _TotalExp = _TotalGet[2];
NormalExp = _TotalExp;
}
NormalResponse.Close();
}
catch (Exception)
{
}
//Normal Ironman
try
{
WebRequest IronScore = WebRequest.Create("https://secure.runescape.com/m=hiscore_oldschool_ironman/index_lite.ws?player=" + player);
WebResponse IronResponse = IronScore.GetResponse();
using (Stream IronDStream = IronResponse.GetResponseStream())
{
StreamReader IronReader = new StreamReader(IronDStream);
string IronResponseFromServer = IronReader.ReadToEnd();
var _Score = IronResponseFromServer.Split('\n');
var _Total = _Score[0];
var _TotalGet = _Total.Split(',');
var _TotalRank = _TotalGet[0];
var _TotalLevel = _TotalGet[1];
var _TotalExp = _TotalGet[2];
IronExp = _TotalExp;
}
IronResponse.Close();
}
catch (Exception)
{
}
//Hardcore Ironman
try
{
WebRequest HCScore = WebRequest.Create("https://secure.runescape.com/m=hiscore_oldschool_hardcore_ironman/index_lite.ws?player=" + player);
WebResponse HCResponse = HCScore.GetResponse();
using (Stream HCDStream = HCResponse.GetResponseStream())
{
StreamReader HCReader = new StreamReader(HCDStream);
string HCResponseFromServer = HCReader.ReadToEnd();
var _Score = HCResponseFromServer.Split('\n');
var _Total = _Score[0];
var _TotalGet = _Total.Split(',');
var _TotalRank = _TotalGet[0];
var _TotalLevel = _TotalGet[1];
var _TotalExp = _TotalGet[2];
HCExp = _TotalExp;
}
HCResponse.Close();
}
catch (Exception)
{
}
//Ultimate Ironman
try
{
WebRequest UIMScore = WebRequest.Create("https://secure.runescape.com/m=hiscore_oldschool_ultimate/index_lite.ws?player=" + player);
WebResponse UIMResponse = UIMScore.GetResponse();
using (Stream UIMDStream = UIMResponse.GetResponseStream())
{
StreamReader UIMReader = new StreamReader(UIMDStream);
string UIMResponseFromServer = UIMReader.ReadToEnd();
var _Score = UIMResponseFromServer.Split('\n');
var _Total = _Score[0];
var _TotalGet = _Total.Split(',');
var _TotalRank = _TotalGet[0];
var _TotalLevel = _TotalGet[1];
var _TotalExp = _TotalGet[2];
UIMExp = _TotalExp;
}
UIMResponse.Close();
}
catch (Exception)
{
}
await ReplyAsync(
$"**Normal: ** {NormalExp}\n" +
$"**Ironman: ** {IronExp}\n" +
$"**Hardcore: ** {HCExp}\n" +
$"**UIM: ** {UIMExp}");
if (Convert.ToInt64(UIMExp) == Convert.ToInt64(NormalExp))
{
await ReplyAsync("Account is a UIM");
}
else if (Convert.ToInt64(HCExp) == Convert.ToInt64(NormalExp))
{
await ReplyAsync("Account is a HC");
}
else if (Convert.ToInt64(IronExp) == Convert.ToInt64(NormalExp) && Convert.ToInt64(IronExp) > Convert.ToInt64(UIMExp + HCExp))
{
if (Convert.ToInt32(UIMExp) > 1)
{
await ReplyAsync("Account is a ~~UIM~~ Normal Ironman");
}
else if (Convert.ToInt64(HCExp) > 1)
{
await ReplyAsync("Account is a ~~HC~~ Normal Ironman");
}
else
{
await ReplyAsync("Account is a Normal Ironman");
}
}
else
{
if (Convert.ToInt64(UIMExp) > 1 && Convert.ToInt64(IronExp) > 1)
{
await ReplyAsync("Account is a ~~UIM~~, ~~Ironman~~, normal player.");
}
else if (Convert.ToInt64(HCExp) > 1 && Convert.ToInt64(IronExp) > 1)
{
await ReplyAsync("Account is a ~~HC~~, ~~Ironman~~, normal player.");
}
else if (Convert.ToInt64(IronExp) > 1 && Convert.ToInt64(HCExp) == 0 && Convert.ToInt64(UIMExp) == 0)
{
await ReplyAsync("Account is a ~~Ironman~~ normal player.");
}
else
{
await ReplyAsync("Account is a Normal Player");
}
}
In general, sending requests is an expensive operation but you can improve it by changing your method.
Try to use HttpClient instead of WebRequest
and I suggest reading about Async/Sync operations

Second await doesn't return proper value in method

I have an ansync method which gets called on an onClick-Event in Android.
In the method a few checks are made and then a search-method is called with await which sends a searchquery and gets a response.
Unfortunatley only the first time the search-method is called the program gets the proper return from the method. If I try using the search-method in the second if-block the search-method returns null.
I checked in the search-method whether it recieves the correct response or not and the problem seems to be in the return part because the correct respone is recieved in the search-method.
My code looks like this:
private async void CreateSearchQuery(object sender, EventArgs e)
{
SearchQuery searchQuery = new SearchQuery();
if (spinnerPosition == FIBU)
{
searchQuery.doctype = "Fibu Rechnungen";
searchQuery.query = new Dictionary<string, string>();
searchQuery.query.Add("belegnr", belegnummer.Text);
prefs = PreferenceManager.GetDefaultSharedPreferences(this);
var token = prefs.GetString("token", "");
ProgressDialog progress = new ProgressDialog(this);
progress.Indeterminate = true;
progress.SetProgressStyle(ProgressDialogStyle.Spinner);
progress.SetMessage("Suche nach Daten....");
progress.SetCancelable(false);
progress.Show();
JArray searchresult = await SearchQuery.SendSearchQuery(searchQuery, token);
progress.Cancel();
FibuDocument[] documents = searchresult.ToObject<FibuDocument[]>();
var intent = new Intent(this, typeof(SearchFibuDetailsActivity));
var json = JsonConvert.SerializeObject(documents);
ISharedPreferencesEditor editor = prefs.Edit();
editor.PutString("searchQuery", json);
editor.Apply();
StartActivity(intent);
}
if (spinnerPosition == AUFTRAGSBELEGE)
{
searchQuery.doctype = "Auftragsbelege";
searchQuery.query = new Dictionary<string, string>();
if(auftragsnummer.Text != "")
{
searchQuery.query.Add("auftragsnr", auftragsnummer.Text);
}
if(gstKode.Text != "")
{
searchQuery.query.Add("gst", gstKode.Text);
}
if(trackTrace.Text != "")
{
searchQuery.query.Add("sttnr", trackTrace.Text);
}
prefs = PreferenceManager.GetDefaultSharedPreferences(this);
var token = prefs.GetString("token", "");
ProgressDialog progress = new ProgressDialog(this);
progress.Indeterminate = true;
progress.SetProgressStyle(ProgressDialogStyle.Spinner);
progress.SetMessage("Suche nach Daten....");
progress.SetCancelable(false);
progress.Show();
JArray searchresult = await SearchQuery.SendSearchQuery(searchQuery, token);
progress.Cancel();
Document[] documents = searchresult.ToObject<Document[]>();
var json = JsonConvert.SerializeObject(documents);
Use different instances of "searchQuery" rather than sharing one.

Jira REST API returning HTML

I am trying to access the Jira rest API via C#. For that I am using the Windows.Web.Http.HttpClient. But all I get as a return value is HTML.
I am calling the following URL: https://jira.atlassian.com/rest/api/latest/field/
Little Edit
When I call the url from a browser it works fine, just the call from the HttpClient doesn't work.
Here is my code:
public async Task<IRestResponse> Execute(RestRequest request) {
var restResponse = new RestResponse();
var client = new HttpClient();
var req = new HttpRequestMessage(request.Method, new Uri(BaseUrl, UriKind.RelativeOrAbsolute));
foreach (var item in request.headers) {
req.Headers[item.Key] = item.Value;
}
req.Headers.Accept.Add(new HttpMediaTypeWithQualityHeaderValue("application/json"));
if (this.Authenticator != null)
req.Headers["Authorization"] = this.Authenticator.GetHeader();
var res = await client.SendRequestAsync(req);
restResponse.Content = await res.Content.ReadAsStringAsync();
restResponse.StatusCode = res.StatusCode;
restResponse.StatusDescription = res.ReasonPhrase;
if (!res.IsSuccessStatusCode) {
restResponse.ErrorMessage = restResponse.Content;
restResponse.ResponseStatus = ResponseStatus.Error;
} else if (res.StatusCode == HttpStatusCode.RequestTimeout) {
restResponse.ResponseStatus = ResponseStatus.TimedOut;
} else if (res.StatusCode == HttpStatusCode.None) {
restResponse.ResponseStatus = ResponseStatus.None;
} else {
restResponse.ResponseStatus = ResponseStatus.Completed;
}
return restResponse;
}
I just found my problem, I don't add the relative path anywhere. It just calls the BaseUrl meaning https://jira.atlassian.com/ that explains why I get the HTML page.

C# httpclient hangs at the last request

I have a program which send a couple of thousands of post requests to the server. Everything is working fine until the end of the transmission. After all but one request are sent the program hangs.
Always there is only one request left to make. I am using HttpClient and everything is done async.
Here I create the httpclient:
ServicePointManager.ServerCertificateValidationCallback +=
(sender, cert, chain, sslPolicyErrors) => true;
ServicePointManager.DefaultConnectionLimit = 45;
ServicePointManager.Expect100Continue = false;
var CurrentCredentials = new System.Net.NetworkCredential(Repo.Username, Repo.Password);
var Handler = new HttpClientHandler
{
Credentials = CurrentCredentials,
ClientCertificateOptions = ClientCertificateOption.Automatic,
UseProxy = false,
};
var Client = new HttpClient(Handler);
Client.Timeout = TimeSpan.FromSeconds(2500);
Client.DefaultRequestHeaders.Add("Connection", "Keep-alive");
WebServ = new WebService(Client, ref Repo);
Here is where I send the requests:
private async Task<string> SendData(string Url, HttpContent[] content, string[] name)
{
using (var FormData = new MultipartFormDataContent())
{
for (int i = 0; i < content.Length; ++i)
{
if (name[i] == "file")
FormData.Add(content[i], name[i], name[i] + i.ToString() + ".jpg");
else
FormData.Add(content[i], name[i]);
}
try
{
using (var Response = await Client
.PostAsync(Url, FormData)
.ConfigureAwait(continueOnCapturedContext:false))
{
await App.Current.Dispatcher.BeginInvoke(
(Action)delegate
{
Repo.CurrentItem++;
});
using (var StreamResume = new StreamWriter("resume.bkp"))
{
await StreamResume.WriteLineAsync(Repo.CurrentItem.ToString());
}
if (Response.IsSuccessStatusCode)
{
await App.Current.Dispatcher.BeginInvoke(
(Action)delegate
{
Repo.Log.Add(Url + " OK" + Repo.CurrentItem);
});
}
else
{
await App.Current.Dispatcher.BeginInvoke(
(Action)delegate
{
Repo.Log.Add(Url + " Error "
+ Response.Content.ToString());
});
}
if (Repo.CurrentItem == Repo.NumberOfItems)
{
await App.Current.Dispatcher.BeginInvoke(
(Action)delegate
{
Repo.Log.Add("Data has been imported");
Repo.CurrentState = "Finished!";
Repo.CurrentItem = 0;
Repo.Uploading = false;
Repo.NotUploading = true;
Repo.Resumable = false;
File.Delete("resume.bkp");
});
}
}
return null;
}
catch (OperationCanceledException)
{
}
catch (InvalidOperationException)
{
App.Current.Dispatcher.Invoke(
(Action)delegate
{
Repo.Log.Add("The url is not valid");
Repo.CurrentItem = 0;
});
Client.CancelPendingRequests();
}
return null;
}
}
I encounter no errors whatsoever only that some threads never exit and the program never terminates. If I have a smaller data set, where only about 180 requests are made, the program does the job never hanging. Thanks in advance for your help

How to stop synchronous request to server in c#?

I know this has been asked before but my case is different. because i have no idea what the following code does. i am just using it as third party open source tool.
I am using open source tool "UnityHTTP" to get response from server.
I would like to get response request cancelled if it is taking a long time.
I am not an expert of C# so i couldn't understand what's going on inside the code the tool provided.
I'd appreciate if someone could help me out here.
the code for getting response is as follows
private void GetResponse() {
System.Diagnostics.Stopwatch curcall = new System.Diagnostics.Stopwatch();
curcall.Start();
try {
var retry = 0;
while (++retry < maximumRetryCount) {
if (useCache) {
string etag = "";
if (etags.TryGetValue (uri.AbsoluteUri, out etag)) {
SetHeader ("If-None-Match", etag);
}
}
SetHeader ("Host", uri.Host);
var client = new TcpClient ();
client.Connect (uri.Host, uri.Port);
using (var stream = client.GetStream ()) {
var ostream = stream as Stream;
if (uri.Scheme.ToLower() == "https") {
ostream = new SslStream (stream, false, new RemoteCertificateValidationCallback (ValidateServerCertificate));
try {
var ssl = ostream as SslStream;
ssl.AuthenticateAsClient (uri.Host);
} catch (Exception e) {
Debug.LogError ("Exception: " + e.Message);
return;
}
}
WriteToStream (ostream);
response = new Response ();
response.request = this;
state = RequestState.Reading;
response.ReadFromStream(ostream);
}
client.Close ();
switch (response.status) {
case 307:
case 302:
case 301:
uri = new Uri (response.GetHeader ("Location"));
continue;
default:
retry = maximumRetryCount;
break;
}
}
if (useCache) {
string etag = response.GetHeader ("etag");
if (etag.Length > 0)
etags[uri.AbsoluteUri] = etag;
}
} catch (Exception e) {
Console.WriteLine ("Unhandled Exception, aborting request.");
Console.WriteLine (e);
exception = e;
response = null;
}
state = RequestState.Done;
isDone = true;
responseTime = curcall.ElapsedMilliseconds;
if ( completedCallback != null )
{
if (synchronous) {
completedCallback(this);
} else {
// we have to use this dispatcher to avoid executing the callback inside this worker thread
ResponseCallbackDispatcher.Singleton.requests.Enqueue( this );
}
}
if ( LogAllRequests )
{
#if !UNITY_EDITOR
System.Console.WriteLine("NET: " + InfoString( VerboseLogging ));
#else
if ( response != null && response.status >= 200 && response.status < 300 )
{
Debug.Log( InfoString( VerboseLogging ) );
}
else if ( response != null && response.status >= 400 )
{
Debug.LogError( InfoString( VerboseLogging ) );
}
else
{
Debug.LogWarning( InfoString( VerboseLogging ) );
}
#endif
}
}
I can see that it something has to do with
the following line lines:-
System.Diagnostics.Stopwatch curcall = new System.Diagnostics.Stopwatch();
curcall.Start();
The request is being made using the TcpClient class. It has a two properties ReceiveTimeout and SendTimeout. After the TcpClient has been initialized, set the a desired value for both of these properties before the connection is made:
var client = new TcpClient ();
client.ReceiveTimeout = 2000; // 2 seconds
client.SendTimeout = 2000; // 2 seconds
Doing this will cause the TcpClient to automatically cancel the request when the timeout has reached.
FYI - The below is only used for measurement of how long the request took.
System.Diagnostics.Stopwatch curcall = new System.Diagnostics.Stopwatch();
curcall.Start();
...
responseTime = curcall.ElapsedMilliseconds;

Categories