httpwebrequest GET retry when connection is lost - c#

My application uses a httpwebrequest to GET certain information from my WebAPI. What I'm trying to do is retry the request if the connection is lost or if there is no connection at all.
public static string httpsGET(string passedweburi, string BCO)
{
string content = "";
//GET method
HttpWebRequest HttpRequest = (HttpWebRequest)WebRequest.Create(passedweburi + BCO);
HttpRequest.Method = "GET";
//Response
HttpWebResponse response = (HttpWebResponse)HttpRequest.GetResponse();
StreamReader sr = new StreamReader(response.GetResponseStream(), System.Text.Encoding.GetEncoding("UTF-8"));
content = sr.ReadToEnd();
string resp = content.TrimStart('[').TrimEnd(']').TrimStart('"').TrimEnd('"');
if (resp == "\"The request is invalid.\"")
{
return "VALIDATE Me";
}
else
{
return resp;
}
}
It usually stops at the response variable then throws the exception from the method that calls this method, that there is no connection. I am thinking of making a while loop to make a countdown to reconnect for about an hour perhaps. Something like this:
int rt = 0;
while (rt < 60)
{
if (resp == "\"Unable to connect to the remote server.\"")
{
Console.Writeline("Connection Timed Out");
Console.Writeline("Re-establishing connection...");
DateTime startTime = DateTime.Now;
while (true)
{
if (DateTime.Now.Subtract(startTime).TotalMilliseconds > 60000)
break;
}
rt++;
Console.Writeline("Retrying " + rt.ToString() + " times");
}
if (rt >= 60)
{
Console.Writeline("Failed to reconnect.");
}
Any advise?

//this is by no means pretty, but im using your code verbatim
` public static string httpsGET(string passedweburi, string BCO)
{
string content = "";
//GET method
HttpWebRequest HttpRequest = (HttpWebRequest)WebRequest.Create(passedweburi + BCO);
HttpRequest.Method = "GET";
//Response
try
{
HttpWebResponse response = (HttpWebResponse)HttpRequest.GetResponse();
}
catch(Exception ex)
{
return "failed";
}
StreamReader sr = new StreamReader(response.GetResponseStream(), System.Text.Encoding.GetEncoding("UTF-8"));
content = sr.ReadToEnd();
string resp = content.TrimStart('[').TrimEnd(']').TrimStart('"').TrimEnd('"');
if (resp == "\"The request is invalid.\"")
{
return "VALIDATE Me";
}
else
{
return resp;
}
}
//calling your method
string resp = "";
while (rt < 60)
{
if (rt >= 60)
{
Console.Writeline("Failed to reconnect.");
}
resp = YourStaticObj.httpsGET("http://bla","bco")
if (resp == "failed")
{
Console.Writeline("Connection Timed Out");
Console.Writeline("Re-establishing connection...");
DateTime startTime = DateTime.Now;
System.Threading.Thread.Sleep(60000);
Console.Writeline("Retrying " + rt.ToString() + " times");
}
}

Related

API Call not successful

Good day Guys,
I am trying to Use an SMS API. Everything looks fine from my end but the SMS is not delivering. If i use the URL directly on Browser, it executes.
Or is anything wrong with how i built the string?
Below is the code.
Please Note tht cbo.Title is a comobox, txtFirstname is a Textbox.
public void NewText()
{
string username = "something#gmail.com";
string password = "Password";
string urlStr;
string message=" Dear " + cbo_Title.Text + " " + txt_FirstName.Text + ", Your New Savings Account Number is " + Account_No + ".Welcome to AGENTKUNLE Global Services. Your Future is Our Priority ";
string sender = "AGENTKUNLE";
string recipient=txt_Phone.Text;
urlStr = "https://portal.nigeriabulksms.com/api/?username="+username+"+password="+password+"+sender="+sender+"+message="+message+"+ mobiles="+recipient;
Uri success = new Uri(urlStr);
}
private string SendSms(string apiUrl)
{
var targetUri = new Uri(apiUrl);
var webRequest = (HttpWebRequest) WebRequest.Create(targetUri);
webRequest.Method = WebRequestMethods.Http.Get;
try
{
string webResponse;
using (var getresponse = (HttpWebResponse) webRequest.GetResponse())
{
var stream = getresponse.GetResponseStream();
if (stream != null)
using (var reader = new StreamReader(stream))
{
webResponse = reader.ReadToEnd();
reader.Close();
}
else
webResponse = null;
getresponse.Close();
}
if (!string.IsNullOrEmpty(webResponse?.Trim()))
return webResponse.Trim();
}
catch (WebException ex)
{
ErrorHelper.Log(ex);
}
catch (Exception ex)
{
ErrorHelper.Log(ex);
}
finally
{
webRequest.Abort();
}
return null;
}
You never make a request.
The Uri object is just a container for the uri (see Microsoft Docs).
Check out the HttpClient class if you want to send a request.

HttpWebRequest.GetRequestStream() stall after second attempt (asynch) c#

my environment version is 2.0, I am currently working with Unity 5.5, c#.
I am experiencing a stall the 3rd time i try to get an HttpWebRequest request stream.
What I want to achieve is having a mechanism of "retry": when I send a request I wait for the response and if it times out I send another request and refresh the time out. I stop this loop when I hit MAX_ATTEMPTS or one of the requests get a response (even if it is from a request that has timed out).
The code that handles this loop is here:
IEnumerator DoRequest()
{
List<IAsyncResult> results = new List<IAsyncResult>(MAX_ATTEMPTS);
int attemptNumber = 1;
while (attemptNumber <= MAX_ATTEMPTS)
{
IAsyncResult result = null;
try
{
result = SendRequest();
}
catch (Exception e)
{
ProcessException(e);
yield break;
}
if (result != null)
{
results.Add(result);
DateTime timeOutTime = DateTime.UtcNow + TIMEOUT;
yield return null;
while (DateTime.UtcNow < timeOutTime)
{
int completedIndex = -1;
if (IsAnyResultCompleted(results, out completedIndex) == true)
{
ProcessResponse(results[completedIndex]);
yield break;
}
else
{
yield return null;
}
}
}
attemptNumber++;
}
if (results.Count != 0)
{
ProcessResponseFail("Timed out");
}
else
{
ProcessResponseFail("Unable to generate a request");
}
}
Where TIMEOUT is a TimeSpan of 10 seconds. And IsAnyResultCompleted is just a for loop that checks if any request has IsCompleted set to true.
Here I create and send the request:
IAsyncResult SendRequest()
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(RequestActionPath);
request.ContentType = "application/json";
request.Accept = "application/json";
request.Method = "POST";
string json = JsonUtility.ToJson(_dependency);
using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
{
sw.Write(json);
sw.Flush();
}
IAsyncResult result = request.BeginGetResponse(new AsyncCallback(onResponse), request);
return result;
}
"onResponse" is a cached delegate and it is assigned to this:
void OnResponse(IAsyncResult asynchronousResult)
{
try
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
request.EndGetResponse(asynchronousResult);
}
catch (WebException e)
{
string responseStream;
using (var streamReader = new StreamReader(e.Response.GetResponseStream()))
{
responseStream = streamReader.ReadToEnd();
}
Utility.Console.LogError(responseStream);
}
}
I am well aware of this and I also tried to set ServicePointManager.DefaultConnectionLimit = 1000000 but the result is always the same, after 2 sent requests GetRequestStream() in SendRequest stalls for 5 seconds and I cannot understand why.

HttpWebRequest.GetRequestStream() Timeout

I have a service that builds an HttpWebRequest and sets its body with a JSON string to be sent to a system's API. At the point of calling for the request stream, I am ocassionaly getting a WebException timeout error. Why would it error at this point? Does it test connecting to the other system before continuing?
try
{
//Get default request data
if (requestObj == null)
requestObj = new ApiRequest();
//Convert request info to json+bytes
string url = _baseUrl + path;
string requestStr = JsonConvert.SerializeObject(requestObj, _jsonSettings);
requestObjJson = requestStr;
byte[] data = Encoding.UTF8.GetBytes(requestStr);
//Post to SystemX
webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.ContentType = "application/json;charset=UTF-8";
webRequest.Headers.Add("access_token", _accessToken);
webRequest.Method = "POST";
webRequest.ContentLength = data.Length;
webRequestJson = JsonConvert.SerializeObject(webRequest, Formatting.Indented);
using (Stream dataStream = webRequest.GetRequestStream())
{
dataStream.Write(data, 0, data.Length);
dataStream.Close();
}
webRequestJson = JsonConvert.SerializeObject(webRequest, Formatting.Indented);
LogMessage("SystemXApiAdapter._request() Request", "Information only. Not an error.", webRequestJson + ";" + requestObjJson, connectionString, customerName, licenseInfoID);
//Get response
string responseString = null;
HttpStatusCode status;
using (HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse())
{
if (response != null)
{
using (Stream stream = response.GetResponseStream())
using (StreamReader sr = new StreamReader(stream))
{
responseString = sr.ReadToEnd();
status = response.StatusCode;
}
response.Close();
}
else
{
status = HttpStatusCode.NoContent;
}
}
T responseObj = null;
LogMessage("SystemXApiAdapter._request() Response", "Information only. Not an error.", responseString, connectionString, customerName, licenseInfoID);
if (typeof(T) == typeof(EmptyApiResponse))
return null;
if (string.IsNullOrEmpty(responseString))
throw new Exception("Empty response for non-empty request");
responseObj = JsonConvert.DeserializeObject<T>(responseString);
if (callback != null)
callback(responseObj);
//Get next page of data if needed
if (handlePaging && status == HttpStatusCode.PartialContent)
{
//Move to next page and recursively make more requests until we've got everything
requestObj.page_num++;
T moreData = _request<T>(path, connectionString, customerName, licenseInfoID, true, requestObj, callback);
if (moreData != null)
responseObj = (T)(responseObj).AppendResponseData(moreData);
}
return responseObj;
}
catch (Exception ex)
{
SystemXApiException SystemXEx = new SystemXApiException(requestObj, ex, webRequestJson);
if (!bIsRetry && SystemXEx.StatusCode.HasValue && retryOnStatuses.Contains(SystemXEx.StatusCode.Value))
{
return _request<T>(path, connectionString, customerName, licenseInfoID, handlePaging, requestObj, callback, true);
}
else
{
throw SystemXEx;
}
if (ex is WebException)
{
WebException webEx = (WebException)ex;
HttpStatusCode? StatusCode = null;
string responseBody = null;
//Read Status Code
if (webEx.Status == WebExceptionStatus.ProtocolError)
{
var response = webEx.Response as HttpWebResponse;
if (response != null)
{
StatusCode = response.StatusCode;
}
}
//Retry once on applicable status code
if (!bIsRetry && StatusCode.HasValue && retryOnStatuses.Contains(StatusCode.Value))
return _request<T>(path, connectionString, customerName, licenseInfoID, handlePaging, requestObj, callback, true);
//Read response Body
if (webEx.Response != null)
{
using (Stream responseStream = webEx.Response.GetResponseStream())
using (StreamReader sr = new StreamReader(responseStream, Encoding.Default))
{
responseBody = sr.ReadToEnd();
}
}
else
{
responseBody = "Empty response body.";
}
string message = null;
//Format new Exception
if (StatusCode.HasValue)
message = string.Format("{0} {1}: {2}: {3}: {4}", (int)StatusCode, StatusCode.ToString(), responseBody, requestObjJson, webRequestJson);
else
message = string.Format("{0} {1}: {2}: {3}: {4}", "No status code", "No status code", responseBody, requestObjJson, webRequestJson);
throw new Exception(message, ex);
}
else
throw;
}
finally
{
if (webRequest != null)
{
webRequest.Abort();
}
}
One option is to increase the time limit.
https://msdn.microsoft.com/pt-br/library/system.net.httpwebrequest.timeout(v=vs.110).aspx
webRequest.Timeout=2000; (2 seconds)
Another is to repeat the execution after a timeout, waiting x seconds.
Any connection can go through problems, your code need to be prepared for this.
I hope it helped in someway.

How do I reissue a webrequest? Must I recreate Webclient?

The following code gets stuck in a while loop when an exception is encountered. This is because GetResponse is caching the data.
According to fiddler, no data after the first request is issued.
Is it a best practice to recreate the webclient to solve the "refresh" issue I'm having?
private static ReportStatusEnum GetReportStatus(string domain, string oAuthKey, long permissionReportID)
{
string target = string.Format("https://{0}.egnyte.com/pubapi/v1/audit/jobs/{1}", domain, permissionReportID);
var client = new WebClient();
string result ="";
var request = (HttpWebRequest)WebRequest.Create(target);
request.ContentType = "application/json";
request.Headers.Add("Authorization", "Bearer " + oAuthKey);
request.AllowAutoRedirect = false;
bool callComplete = false;
while (callComplete != true)
{
try
{
using (var response = request.GetResponse())
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
result = reader.ReadToEnd();
}
}
JToken result2 = JObject.Parse(result);
var statusResult = result2.SelectToken("status");
ReportStatusEnum ret = ReportStatusEnum.error;
Enum.TryParse<ReportStatusEnum>(statusResult.ToString(), out ret);
Console.WriteLine("The returned variable is:" + ret);
callComplete = true;
return ret;
}
catch (System.Net.WebException e)
{
if (e.Response != null)
if (e.Response.ContentLength > 0)
{
if (e.Response.Headers["X-Mashery-Error-Code"] == "ERR_403_DEVELOPER_OVER_QPS")
{
Thread.Sleep(60000); Console.Write("*QPS HIT*");
}
}
}
}
return ReportStatusEnum.error;
}
No. HttpWebRequests are not reusable.
Just move the creation of your WebRequest into the body of your loop:
string result ="";
bool callComplete = false;
while (callComplete != true)
{
var request = (HttpWebRequest)WebRequest.Create(target);
request.ContentType = "application/json";
request.Headers.Add("Authorization", "Bearer " + oAuthKey);
request.AllowAutoRedirect = false;
//...

can I check if a file exists at a URL?

I know I can locally, on my filesystem, check if a file exists:
if(File.Exists(path))
Can I check at a particular remote URL?
If you're attempting to verify the existence of a web resource, I would recommend using the HttpWebRequest class. This will allow you to send a HEAD request to the URL in question. Only the response headers will be returned, even if the resource exists.
var url = "http://www.domain.com/image.png";
HttpWebResponse response = null;
var request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "HEAD";
try
{
response = (HttpWebResponse)request.GetResponse();
}
catch (WebException ex)
{
/* A WebException will be thrown if the status of the response is not `200 OK` */
}
finally
{
// Don't forget to close your response.
if (response != null)
{
response.Close();
}
}
Of course, if you want to download the resource if it exists it would most likely be more efficient to send a GET request instead (by not setting the Method property to "HEAD", or by using the WebClient class).
If you want to just copy & paste Justin's code and get a method to use, here's how I've implemented it:
using System.Net;
public class MyClass {
static public bool URLExists (string url) {
bool result = false;
WebRequest webRequest = WebRequest.Create(url);
webRequest.Timeout = 1200; // miliseconds
webRequest.Method = "HEAD";
HttpWebResponse response = null;
try {
response = (HttpWebResponse)webRequest.GetResponse();
result = true;
} catch (WebException webException) {
Debug.Log(url +" doesn't exist: "+ webException.Message);
} finally {
if (response != null) {
response.Close();
}
}
return result;
}
}
I'll keep his observation:
If you want to download the resource, and it exists, it would be more efficient to send a GET request instead by not setting the Method property to "HEAD" or by using the WebClient class.
Below is a simplified version of the code:
public bool URLExists(string url)
{
bool result = true;
WebRequest webRequest = WebRequest.Create(url);
webRequest.Timeout = 1200; // miliseconds
webRequest.Method = "HEAD";
try
{
webRequest.GetResponse();
}
catch
{
result = false;
}
return result;
}
If you are using a unc path or a mapped drive, this will work fine.
If you are using a web address (http, ftp etc) you are better off using WebClient - you will get a WebException if it doesn't exist.
public static bool UrlExists(string file)
{
bool exists = false;
HttpWebResponse response = null;
var request = (HttpWebRequest)WebRequest.Create(file);
request.Method = "HEAD";
request.Timeout = 5000; // milliseconds
request.AllowAutoRedirect = false;
try
{
response = (HttpWebResponse)request.GetResponse();
exists = response.StatusCode == HttpStatusCode.OK;
}
catch
{
exists = false;
}
finally
{
// close your response.
if (response != null)
response.Close();
}
return exists;
}
I had the same problem to solve in asp.net core, I've solved with HttpClient
private async Task<bool> isFileExist(string url)
{
using (HttpClient client = new HttpClient())
{
var restponse = await client.GetAsync(url);
return restponse.StatusCode == System.Net.HttpStatusCode.OK;
}
}
My version:
public bool IsUrlExist(string url, int timeOutMs = 1000)
{
WebRequest webRequest = WebRequest.Create(url);
webRequest.Method = "HEAD";
webRequest.Timeout = timeOutMs;
try
{
var response = webRequest.GetResponse();
/* response is `200 OK` */
response.Close();
}
catch
{
/* Any other response */
return false;
}
return true;
}
WebRequest will waiting long time(ignore the timeout user set) because not set proxy, so I change to use RestSharp to do this.
var client = new RestClient(url);
var request = new RestRequest(Method.HEAD);
request.Timeout = 5000;
var response = client.Execute(request);
result = response.StatusCode == HttpStatusCode.OK;
Thanks for all answers.
And I would like to add my implementation which includes default state when we get errors, for specific cases like mine.
private bool HTTP_URLExists(String vstrURL, bool vResErrorDefault = false, int vTimeOut = 1200)
{
bool vResult = false;
WebRequest webRequest = WebRequest.Create(vstrURL);
webRequest.Timeout = vTimeOut; // miliseconds
webRequest.Method = "HEAD";
HttpWebResponse response = null;
try
{
response = (HttpWebResponse)webRequest.GetResponse();
if (response.StatusCode == HttpStatusCode.OK) vResult = true;
else if (response.StatusCode == HttpStatusCode.NotFound) vResult = false;
else vResult = vResErrorDefault;
}
catch (WebException ex)
{
if (ex.Status == WebExceptionStatus.ProtocolError && ex.Response != null)
{
var resp01 = (HttpWebResponse)ex.Response;
if (resp01.StatusCode == HttpStatusCode.NotFound)
{
vResult = false;
}
else
{
vResult = vResErrorDefault;
}
}
else
{
vResult = vResErrorDefault;
}
}
finally
{
// Don't forget to close your response.
if (response != null)
{
response.Close();
}
}
return vResult;
}
Anoter version with define timeout :
public bool URLExists(string url,int timeout = 5000)
{
...
webRequest.Timeout = timeout; // miliseconds
...
}
This works for me:
bool HaveFile(string url)
{
try
{
using (WebClient webClient = new WebClient())
{
webClient.DownloadString(url);
}
return true;
}
catch (Exception)
{
return false;
}
}

Categories