HttpWebRequest.GetRequestStream() Timeout - c#

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.

Related

How to properly post data using begin/end GetRequestStream and callbacks

I'm trying to post a piece of data but it seems to be getting caught and hangs (but not throwing an error).
internal IAsyncResult RequestGet<TPostType>(Action<string> callback, string path, TPostType value)
{
var http = (HttpWebRequest)WebRequest.Create(Connection.GetUri(path).Uri);
http.Accept = "application/json";
http.ContentType = "application/json";
http.Method = "POST";
var parsedContent = JsonConvert.SerializeObject(value);
var encoding = new ASCIIEncoding();
var bytes = encoding.GetBytes(parsedContent);
return http.BeginGetRequestStream(ar =>
{
try
{
var stream = http.EndGetRequestStream(ar);
stream.Write(bytes, 0, bytes.Length);
stream.Close();
http.BeginGetResponse(body =>
{
// its around here that it hangs.
var response = http.EndGetResponse(ar);
var s = response.GetResponseStream();
ReadStream(callback, s);
}, null);
}
catch (WebException webex)
{
WebResponse errResp = webex.Response;
using (Stream respStream = errResp.GetResponseStream())
{
Console.WriteLine(new StreamReader(respStream).ReadToEnd());
}
}
}, null);
}
There were a few times when it didn't hang but told me that the request body was missing, however I didn't make any progress beyond that. Could someone please inform me as to what I'm doing wrong?
The ReadStream method works for GET requests, but for context:
private static IAsyncResult ReadStream(Action<string> callback, Stream stream)
{
var buffer = new byte[5000];
var asyncResult = stream.BeginRead(buffer, 0, 5000, ar2 =>
{
try
{
callback(Encoding.UTF8.GetString(buffer, 0, 5000));
}
catch (Exception ex)
{
// do better error handling
Console.WriteLine("exception reading stream");
Console.WriteLine(ex);
}
}, null);
return asyncResult;
}
For more context on how its being used:
public IAsyncResult BeginGetChainPart(Action<BlockData.BlockList> callback, int height)
{
var asyncResult = new HttpConnector(Connection).RequestGet(body =>
{
callback(JsonConvert.DeserializeObject<BlockData.BlockList>(body));
}, "/local/chain/blocks-after", new BlockData.BlockHeight { Height = height });
return asyncResult;
}
found the solution, posting in case anyone comes across the same issue:
internal IAsyncResult RequestGet<TPostType>(Action<string> callback, string path, TPostType value)
{
var http = (HttpWebRequest)WebRequest.Create(Connection.GetUri(path).Uri);
http.Accept = "application/json";
http.ContentType = "application/json";
http.Method = "POST";
var parsedContent = JsonConvert.SerializeObject(value);
var encoding = new ASCIIEncoding();
var bytes = encoding.GetBytes(parsedContent);
return http.BeginGetRequestStream(ar => {
try
{
var stream = http.EndGetRequestStream(ar);
stream.Write(bytes, 0, bytes.Length);
stream.Close();
var response = http.GetResponse();
var responseStream = response.GetResponseStream();
ReadStream(callback, responseStream);
}
catch (WebException webex)
{
WebResponse errResp = webex.Response;
using (Stream respStream = errResp.GetResponseStream())
{
StreamReader reader = new StreamReader(respStream);
string text = reader.ReadToEnd();
Console.WriteLine(text);
}
}
}, null);
}

httpwebrequest GET retry when connection is lost

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");
}
}

Return full HTTP Response in ASP.Net WebAPI Controller

I'm trying to return a full HTTP-Response to the browser within an ASP.NET WebAPI Controller.
The scenario is the following:
I make a remote call to another webserver and get a full HTTP-Message including the HTTP Headers and content. I just want do deliver this message "as is" to the browser.
Does anyone know how to do this?
Create your own IHttpHandler and configure a route for it. You have to copy all response headers from your own response to the response object of ASP.NET.
Here is a sample implementation for another scenario:
public class CorsProxyHttpHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
var url = context.Request.Headers["X-CorsProxy-Url"];
if (url == null)
{
context.Response.StatusCode = 501;
context.Response.StatusDescription =
"X-CorsProxy-Url was not specified. The corsproxy should only be invoked from the proxy JavaScript.";
context.Response.End();
return;
}
try
{
var request = WebRequest.CreateHttp(url);
context.Request.CopyHeadersTo(request);
request.Method = context.Request.HttpMethod;
request.ContentType = context.Request.ContentType;
request.UserAgent = context.Request.UserAgent;
if (context.Request.AcceptTypes != null)
request.Accept = string.Join(";", context.Request.AcceptTypes);
if (context.Request.UrlReferrer != null)
request.Referer = context.Request.UrlReferrer.ToString();
if (!context.Request.HttpMethod.Equals("GET", StringComparison.OrdinalIgnoreCase))
context.Request.InputStream.CopyTo(request.GetRequestStream());
var response = (HttpWebResponse)request.GetResponse();
response.CopyHeadersTo(context.Response);
context.Response.ContentType = response.ContentType;
context.Response.StatusCode =(int) response.StatusCode;
context.Response.StatusDescription = response.StatusDescription;
var stream = response.GetResponseStream();
if (stream != null && response.ContentLength > 0)
{
stream.CopyTo(context.Response.OutputStream);
stream.Flush();
}
}
catch (WebException exception)
{
context.Response.AddHeader("X-CorsProxy-InternalFailure", "false");
var response = exception.Response as HttpWebResponse;
if (response != null)
{
context.Response.StatusCode = (int)response.StatusCode;
context.Response.StatusDescription = response.StatusDescription;
response.CopyHeadersTo(context.Response);
var stream = response.GetResponseStream();
if (stream != null)
stream.CopyTo(context.Response.OutputStream);
return;
}
context.Response.StatusCode = 501;
context.Response.StatusDescription = exception.Status.ToString();
var msg = Encoding.ASCII.GetBytes(exception.Message);
context.Response.OutputStream.Write(msg, 0, msg.Length);
context.Response.Close();
}
catch (Exception exception)
{
context.Response.StatusCode = 501;
context.Response.StatusDescription = "Failed to call proxied url.";
context.Response.AddHeader("X-CorsProxy-InternalFailure", "true");
var msg = Encoding.ASCII.GetBytes(exception.Message);
context.Response.OutputStream.Write(msg, 0, msg.Length);
context.Response.Close();
}
}
public bool IsReusable { get { return true; }}
}
(from my article: http://blog.gauffin.org/2014/04/how-to-use-cors-requests-in-internet-explorer-9-and-below/)

WebException timeout with HttpWebRequest.GetRequestStream() in Monotouch

I still working on learning Xamarin.iOs and randomly (sometime on the simulator but more often on the device), I've a timeout exception calling HttpWebRequest.GetRequestStream() in an async method. However, I create a new HttpWebRequest each time the method is called and I think I properly close and dispose everything. Here's a snippet of the code :
private async static Task<T> internalCallService<T>(ILogger logger,string url, string body, string httpVerb, string contentType)
{
T result = default(T);
WebRequest wr=null;
try
{
logger.Log("Calling {0} started", url);
wr = HttpWebRequest.Create(url);
wr.ContentType = contentType;
wr.Method = httpVerb;
wr.Timeout = DEFAULT_TIMEOUT;
byte[] streamContent = System.Text.Encoding.UTF8.GetBytes(body);
using (Stream dataStream = wr.GetRequestStream())
{
dataStream.Write(streamContent, 0, streamContent.Length);
dataStream.Flush();
dataStream.Close();
var sw = new Stopwatch();
sw.Start();
using (var response = (await wr.GetResponseAsync().ConfigureAwait(false)))
{
if (response != null)
{
sw.Stop();
logger.Log("Time to call {0} : {1} ms", url, sw.ElapsedMilliseconds);
try
{
var webResponse = response as HttpWebResponse;
if (webResponse != null && webResponse.StatusCode == HttpStatusCode.OK)
{
using (Stream responseStream = webResponse.GetResponseStream())
{
using (StreamReader reader = new StreamReader(responseStream))
{
var responseText = reader.ReadToEnd();
result = JsonConvert.DeserializeObject<T>(responseText);
reader.Close();
}
responseStream.Close();
}
}
}
finally
{
if (response != null)
{
response.Close();
}
}
}
}
}
}
catch (Exception e)
{
logger.Log(e.GetBaseException().Message);
throw;
}
finally
{
if (wr != null)
{
wr.Abort();
wr = null;
}
}
return result;
}
Any idea what's going on ?
Thanks.

WP8 HttpWebRequest Post Not Working

I have a Windows Phone Application and I I am trying to post data in JSON format to a WCF application. Although the connection is made, the server returns with a custom message with
This is the C# code:
ReportSightingRequest.Instance.Source = Source.IPhone;
var jsonData = JsonConvert.SerializeObject(ReportSightingRequest.Instance);
var uri = new Uri("urlGoesHere", UriKind.Absolute);
var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/json";
request.ContentLength = jsonData.Length;
string received;
using (var response = (HttpWebResponse)(await Task<WebResponse>.Factory.FromAsync(request.BeginGetResponse, request.EndGetResponse, null)))
{
using (var responseStream = response.GetResponseStream())
{
using (var sr = new StreamReader(responseStream))
{
received = await sr.ReadToEndAsync();
}
}
}
This is the WCF Interface:
[OperationContract]
[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
[Description("Description.")]
Response.Response ReportSighting(ReportSightingRequest sighting);
This is the implementation:
public Response ReportSighting(ReportSightingRequest sightingRequest)
{
var response = new Response();
if (sightingRequest == null || sightingRequest.TypeId == null)
{
response.Status = ResponseStatus.InvalidArguments;
response.Message = "Request is null or no type has been supplied.";
return response;
}
...
}
When I call the ReportSighting method form the phone, I get a "Request is null or no type has been supplied" message. The strange thing is that I AM sending a TypeId and the sightingRequest object on the WP8 side is definitely not null when i'm sending it. When I put a breakpoint on the jsonData, it has everything in it. The ReportSightingRequest object too is exactly the same as the ReportSightingRequest in the WCF application.
It almost feels like that the object isn't being serialized. That's the only thing I can think of.
Does anyone have any ideas/suggestions?
Update
I've noticed that i'm actually not sending over the object. Shawn Kendrot's Answer seems to make sense but when I integrate his code, it returns with a Not Found error.
Update
The following code works in a Console App:
var jsonData = "a hard coded JSON string here";
var uri = new Uri("a url goes here", UriKind.Absolute);
var webRequest = (HttpWebRequest)WebRequest.Create(uri);
webRequest.Method = "POST";
webRequest.ContentType = "application/json; charset=utf-8";
webRequest.ContentLength = jsonData.Length;
webRequest.BeginGetRequestStream(ar =>
{
try
{
using (var os = webRequest.EndGetRequestStream(ar))
{
var postData = Encoding.UTF8.GetBytes(jsonData);
os.Write(postData, 0, postData.Length);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
webRequest.BeginGetResponse(
ar2 =>
{
try
{
using (var response = webRequest.EndGetResponse(ar2))
using (var reader = new StreamReader(response.GetResponseStream()))
{
var received = reader.ReadToEnd();
//Console.WriteLine(received);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}, null);
}, null);
Update
I have changed my code in WP8 to match that of Shawn Kendrot's solution. The problem which I am facing here is that I get a Not Found error message:
webRequest.BeginGetRequestStream(ar =>
{
try
{
using (var os = webRequest.EndGetRequestStream(ar))
{
var postData = Encoding.UTF8.GetBytes(jsonData);
os.Write(postData, 0, postData.Length);
}
}
catch (Exception ex)
{
MessageBox.Show("Unsuccessful");
}
webRequest.BeginGetResponse(
ar2 =>
{
try
{
using (var response = webRequest.EndGetResponse(ar2))
using (var reader = new StreamReader(response.GetResponseStream()))
{
var received = reader.ReadToEnd();
}
}
catch (Exception ex)
{
MessageBox.Show("Unsuccessful");
}
}, null);
}, null);
I get a:
{System.UnauthorizedAccessException: Invalid cross-thread access.
at MS.Internal.XcpImports.CheckThread()
at MS.Internal.XcpImports.MessageBox_ShowCore(String messageBoxText, String caption, UInt32 type)
at System.Windows.MessageBox.ShowCore(String messageBoxText, String caption, MessageBoxButton button)
at System.Windows.MessageBox.Show(String messageBoxText)
at Notify.Logic.WebServices.<>c_DisplayClass2.b_1(IAsyncResult ar2)
at System.Net.Browser.ClientHttpWebRequest.<>c_DisplayClass1d.b_1b(Object state2)}
When I try to do `MessageBox.Show(ex.Message);
Update
I have fixed the issue with the MessageBox.Show error message.
The webRequest.Headers object has the following:
{Content-Type: application/json; charset=utf-8;}
Your sightingRequest is null because you are not sending any data. To send data using a WebRequest, you need to use the BeginGetRequestStream method. This method allows you to package the data.
var webRequest= (HttpWebRequest)WebRequest.Create(uri);
webRequest.Method = "POST";
webRequest.ContentType = "application/json";
webRequest.ContentLength = jsonData.Length;
webRequest.BeginGetRequestStream(ar =>
{
try
{
using (Stream os = webRequest.EndGetRequestStream(ar))
{
var postData = Encoding.UTF8.GetBytes(jsonData);
os.Write(postData, 0, postData.Length);
}
}
catch (Exception ex)
{
// Do something, exit out, etc.
}
webRequest.BeginGetResponse(
ar2 =>
{
try
{
using (var response = webRequest.EndGetResponse(ar2))
using (var reader = new StreamReader(response.GetResponseStream()))
{
string received = reader.ReadToEnd();
}
}
catch (Exception ex)
{
// Do something, exit out, etc.
}
}, null);
}, null);

Categories