I have been running a C# TCP server, which is transferring data to another server via HTTP POST calls for 2 years with no issues.
After switching from Windows server 2008 to 2012, the requests are taking forever. On the "receiving" side, it is so slow, that I am running out of threads and getting 508 errors back. I have timed the scripts which is requested via HTTP. It takes around 30-40 ms to execute. No worries.
If I time the amount of time it takes to make the HttpWebRequest it is around 2 seconds, which must be why I am running out of threads on the web server.
This is my request code:
public static string WRequest(string URL, string method, string postData)
{
string responseData = "";
try
{
ServicePointManager.Expect100Continue = false;
ServicePointManager.UseNagleAlgorithm = false;
ServicePointManager.CheckCertificateRevocationList = false;
// System.Net.CookieContainer cookieJar = new System.Net.CookieContainer();
System.Net.HttpWebRequest hwrequest =
(System.Net.HttpWebRequest)System.Net.WebRequest.Create(URL);
// hwrequest.CookieContainer = cookieJar;
hwrequest.Accept = "*/*";
hwrequest.AllowAutoRedirect = true;
hwrequest.UserAgent = "http_requester/0.1";
hwrequest.Timeout = 60000;
hwrequest.Proxy = null;
hwrequest.Method = method;
if (hwrequest.Method == "POST")
{
hwrequest.ContentType = "application/x-www-form-urlencoded";
// Use UTF8Encoding instead of ASCIIEncoding for XML requests:
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
byte[] postByteArray = encoding.GetBytes(postData);
hwrequest.ContentLength = postByteArray.Length;
System.IO.Stream postStream = hwrequest.GetRequestStream();
postStream.Write(postByteArray, 0, postByteArray.Length);
postStream.Close();
}
System.Net.HttpWebResponse hwresponse =
(System.Net.HttpWebResponse)hwrequest.GetResponse();
if (hwresponse.StatusCode == System.Net.HttpStatusCode.OK)
{
System.IO.Stream responseStream = hwresponse.GetResponseStream();
System.IO.StreamReader myStreamReader =
new System.IO.StreamReader(responseStream);
responseData = myStreamReader.ReadToEnd();
// MessageBox.Show(responseData);
}
hwresponse.Close();
}
catch (Exception e)
{
responseData = "An error occurred: " + e.Message;
Console.WriteLine(e.ToString());
}
Console.WriteLine(responseData);
return responseData;
}
I have tested this on my windows 10 machine, and the server 2012, with the same timing problems (2 seconds).
Any ideas to where the problem might be? I feel like I have tried everything.
Related
I was first getting "Unable to connect to the remote server" but then remembered that I couldn't use "localhost" from a handheld device. I swapped that out with the name of the machine like so:
String uri = String.Format(#"http://PLATYPUS:21608/api/inventory/sendXML/woodrow/gus/{0}", fileName);
//I reckon I could also use the IP address in place of the machine name, but probably would make no difference
...and now I get, "The remote server returned an error: (400) Bad Request"
The same basic code (shown below) runs fine from a "regular" (C# desktop) app created in VS 2013. From the handheld device, with this code created in VS 2003, I get that ("400") err msg. Why might that be?
public static string SendXMLFile(string xmlFilepath, string uri, int timeout)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.KeepAlive = false;
request.ProtocolVersion = HttpVersion.Version10;
request.ContentType = "application/xml";
request.Method = "POST";
StringBuilder sb = new StringBuilder();
using (StreamReader sr = new StreamReader(xmlFilepath))
{
String line;
while ((line = sr.ReadLine()) != null)
{
sb.Append(line);
sb.Append("\r\n");
}
byte[] postBytes = Encoding.UTF8.GetBytes(sb.ToString());
if (timeout < 0)
{
request.Timeout = timeout;
}
request.ContentLength = postBytes.Length;
request.KeepAlive = false;
request.ContentType = "application/x-www-form-urlencoded"; // not "text/xml" correct?
try
{
Stream requestStream = request.GetRequestStream();
requestStream.Write(postBytes, 0, postBytes.Length);
requestStream.Close();
HttpWebResponse response = (HttpWebResponse) request.GetResponse();
return response.ToString();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
request.Abort();
return string.Empty;
}
}
}
This code differs only slightly from that in the VS 2013 app, in these ways:
(a) Above/not working:
sb.Append(line);
sb.Append("\r\n");
Below/working:
sb.AppendLine(line);
(b) Above/not working:
request.Timeout = timeout;
Below/working:
request.ReadWriteTimeout = timeout;
request.Timeout = timeout;
(c) Above/not working:
HttpWebResponse response = (HttpWebResponse) request.GetResponse();
return response.ToString();
Below/working:
using (var response = (HttpWebResponse)request.GetResponse())
{
return response.ToString();
}
VS 2013 code that works:
public static string SendXMLFile(string xmlFilepath, string uri, int timeout)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.KeepAlive = false;
request.ProtocolVersion = HttpVersion.Version10;
request.ContentType = "application/xml";
request.Method = "POST";
StringBuilder sb = new StringBuilder();
using (StreamReader sr = new StreamReader(xmlFilepath))
{
String line;
while ((line = sr.ReadLine()) != null)
{
sb.AppendLine(line);
}
byte[] postBytes = Encoding.UTF8.GetBytes(sb.ToString());
if (timeout < 0)
{
request.ReadWriteTimeout = timeout;
request.Timeout = timeout;
}
request.ContentLength = postBytes.Length;
request.KeepAlive = false;
request.ContentType = "application/x-www-form-urlencoded"; // not "text/xml" correct?
try
{
Stream requestStream = request.GetRequestStream();
requestStream.Write(postBytes, 0, postBytes.Length);
requestStream.Close();
using (var response = (HttpWebResponse)request.GetResponse())
{
return response.ToString();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
request.Abort();
return string.Empty;
}
}
}
The working code (no err msgs, and the file is saved to the hard drive) passes this to SendXMLFile():
xmlFilepath == "C:\\HoldingTank\\Bla123456789.xml"
uri == http://localhost:21608/api/inventory/sendXML/woodrow/gus/Bla123456789
timeout == 500
The failing code (err msg, file is created and saved, but it is empty) passes:
xmlFilepath == "Bla123456789.xml"
uri == http://SHANNON2:21608/api/inventory/sendXML/woodrow/gus/Bla123456789
timeout == 500
(the ".xml" is stripped out of xmlFilePath before passing that string to the server on the URI)
As to whether the file in xmlFilePath exists in the failing code, I've got this code:
public static bool WriteIt2( string fileName, string data, long fsize )
{
bool retVal = false;
long bytRd = 0;
string the_Msg = "";
if (File.Exists(fileName))
File.Delete(fileName);
using (FileStream fs = File.Create(#fileName))
{
Byte[] info = new UTF8Encoding(true).GetBytes(data);
fs.Write(info, 0, info.Length);
fs.Flush();
}
if (!File.Exists(fileName))
{
MessageBox.Show(String.Format("{0} does not seem to exist", fileName));
}
else
{
MessageBox.Show(String.Format("{0} DOES seem to exist", fileName));
}
string justFileName = Path.GetFileNameWithoutExtension(fileName);
String uri = String.Format(#"http://PLATYPUS:21608/api/inventory/sendXML/woodrow/gus/{0}", fileName);
. . .
...and I do see the "...DOES seem to exist" affirmation message.
Does the filename need to have "\" (or something else) prepended to it?
Is the file writing (FileStream) code wrong?
UPDATE
I tried it with slightly different FileStream code:
Byte[] info = Encoding.ASCII.GetBytes(data);
using (FileStream fileTest = File.Open(fileName, FileMode.CreateNew))
{
fileTest.Write(info, 0, info.Length);
fileTest.Flush();
}
. . .
...but still get the same "400" error.
UPDATE 2
Also with a UTF8 byte array instead of an ASCII byte array:
Byte[] info = Encoding.UTF8.GetBytes(data);
...still get the same err...
UPDATE 3
I realized I was making a boo-boo here:
string justFileName = Path.GetFileNameWithoutExtension(fileName);
. . .
SendXMLFile(fileName, uri, 500);
...and so changed it to:
SendXMLFile(justFileName, uri, 500);
...and now I get a "File not found" exception.
How can it pass the File.Exists test and then not be found?
UPDATE 4
Okay, something really crazy is going on, because I copied a file to the handheld device, into the folder where the .exe/.dll are located, and assigned its name to "justFileName"; it still says the file cannot be found.
Alright, Fiddler here I come...
UPDATE 5
Okay, here's what I see in Fiddler with the server running and then I try to send the file from the handheld device:
Not much appears in Fiddler before the attempt to send the file fails/aborts, and what does display in Fiddler doesn't seem overly helpful.
I wonder if it's not even getting to the point of sending any Http traffic from the handheld? Since I get "File not Found" there's a good chance that's true - why would it try to send it, if it can't find it?
UPDATE 6
As far as a possible header difference (still don't see anything related to my HTTP traffic in Fiddler), I would think I would think I might get a report from Fiddler about that if it was a problem, because I got this due to yahoo Ads bad acting (apparently):
UPDATE 7
I fixed the problem with the file not being found, but that takes me back to the "400" err. Odder yet, I have a breakpoint on the server code (on the "String saveLoc = " line), but it is not getting reached...???
[Route("api/inventory/sendXML/{userId}/{pwd}/{filename}")]
public async void SendInventoryXML(String userId, String pwd, String fileName)
{
XDocument doc = XDocument.Load(await Request.Content.ReadAsStreamAsync());
String saveLoc = String.Format(#"C:\HDP\{0}.xml", fileName); // this line has a breakpoint on it, but Rip Van Winkle is not getting poked.
doc.Save(saveLoc);
}
So the err returned from the server is happening even prior to that (breakpointed) line...???
UPDATE 8
In an attempt to understand why the server method is not being reached and I get the "error (400)" msg, I added a bunch of debug strings to see the values of the HttpWebRequest, like so:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
. . .
request.ContentLength = postBytes.Length;
String str;
if (null != request.Address)
{
String str = String.Format("request.Address == {0}", request.Address.ToString());
MessageBox.Show(str);
}
if (null != request.Connection)
{
str = String.Format("connection == {0}", request.Connection.ToString());
MessageBox.Show(str);
}
. . .
if (null != request.ContentLength.ToString())
{
str = String.Format("contentLength == {0}", request.ContentLength.ToString());
MessageBox.Show(str);
}
I added these debug strings for the following "request" (HttpWebRequest) properties:
Address
Connection
ContentType
Expect
MediaType
Referer // Referrer (don't fear the spell-checker)
RequestUri
TransferEncoding
UserAgent
ContentLength
The only ones that display (are not null) are:
Address
ContentType
RequestUri
ContentLength
So the others being null - is that possibly a/the problem?
In the interests of full disclosure, the values displayed are:
Address == http://PLATYPUS:21608/api/Inventory/sendXML/gus/woodrow/INV_0000003_08272014175010
ContentType == application/xml
RequestUri == [same as Address]
ContentLength == 11457215
Note: I still get the "400" err msg following the display of these four values...
UPDATE 9
Should this:
request.KeepAlive = false;
...be set to true instead (or simply left out altogether, as it is apparently true by default?
UPDATE 10
Please see Update 2 here.
I have the following code:
string url = string.Format("http://{0}:{1}/{2}/xml",Address.Host,Address.Port,Address.ContextRoot);
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.Method = "POST";
req.UserAgent = "Foo";
req.ContentType = "text/xml; charset=\"UTF-8\"";
req.KeepAlive = false;
using (Stream reqStream = req.GetRequestStream())
{
SoapEnvelope s = new SoapEnvelope(Address, null);
XmlDocument xmlDoc = s.GenerateXml(message);
xmlDoc.Save(reqStream);
}
result = ReceiveAnswer(req);
private string ReceiveAnswer(HttpWebRequest req)
{
using (HttpWebResponse res = (HttpWebResponse)req.GetResponse())
using (Stream resStream = res.GetResponseStream())
using (StreamReader reader = new StreamReader(resStream))
{
if (res.StatusCode != HttpStatusCode.OK)
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("Failed to post data to http://{0}:{1}", Address.Host, Address.Port).AppendLine();
sb.AppendFormat("Response: {0} {1}", res.StatusCode, res.StatusDescription);
res.Close();
throw new WebException(sb.ToString());
}
String resData = reader.ReadToEnd();
return resData;
}
}
This code works fine, when I'm connecting to an existing server, but I've just tested, that if the server I specify does not exist then this part: (HttpWebResponse)req.GetResponse() will hang. I expected to get a webexception or something in this scenario, because I want to catch it.
I've read it somewhere that this Response has a timeout of 100 seconds, I've waited more than that, but nothing happened. Then I set the Timeout property to 15 seconds, but that didn't help either.
Anyone knows what should I do?
There was no problem with my code, an other part of the company's code causes the problem.
Be very careful with what you're doing.
Timeout method does not apply to the time waiting for the response to be caught.
Timeout counts for the entire life of your connection (meaning request + response).
If you're then setting a too-low timeout time, your program will never catch it. Maybe you could try to raise the Timeout number?
I have a windows service that I am trying to get running on a server. It just posts data to a php page and has further logic based on the response back. This works 100% on my machine and 100% on the server WHEN Anonymous Authenication is turned on for the website(IIS).
What I want to accomplish is to run the site with Windows Authenication turned ON and have my service still work... except when I try this I receive a nice EventLog entry.
"System.IO.IOException: Unable to read data from the transport
connection: An existing connection was forcibly closed by the remote
host"
I am running the service under an account that has all required permissions. So I understand that "CredentialCache.DefaultCredentials" should use this account for authentication( I am not receiving a 401 error ,but not ruling it out )
Below is my HttpPost code, I have set quite a few options from other posts trying to find a solution.
string postData = xml;
//--------------
HttpRequestCachePolicy policy = new HttpRequestCachePolicy MontgP02(HttpRequestCacheLevel.NoCacheNoStore);
HttpWebRequest.DefaultCachePolicy = policy;
byte[] buffer = Encoding.UTF8.GetBytes(postData);
//Initialisation
System.Net.ServicePointManager.Expect100Continue = false;
HttpWebRequest WebReq = (HttpWebRequest)WebRequest.Create(url);
//Credentials
WebReq.UseDefaultCredentials = true;
WebReq.PreAuthenticate = true;
WebReq.Credentials = CredentialCache.DefaultCredentials;
//Request Settings
WebReq.ProtocolVersion = HttpVersion.Version11;
//WebReq.ServicePoint.ConnectionLimit = 1;
WebReq.Method = "POST";
WebReq.ContentType = "application/x-www-form-urlencoded";
//The length of the buffer
WebReq.ContentLength = buffer.Length;
//Set timeout
WebReq.Timeout = 25000;
//Use Proxy or Not
if (useproxy == "ON")
{
WebProxy myProxy = new WebProxy();
// Create a new Uri object.
Uri newUri = new Uri(proxy);
// Associate the new Uri object to the myProxy object.
myProxy.Address = newUri;
WebReq.Proxy = myProxy;
}
try
{
//Send Data
using (Stream requestStream = WebReq.GetRequestStream())
{
// write to stream
//write, and close.
requestStream.Write(buffer, 0, buffer.Length);
}
}
catch (WebException ex) {
MessageLog("ERROR: Sending Data : " + ex.ToString() + ":", "ERROR");
}
//Get Response
try
{
using (System.Net.WebResponse response = WebReq.GetResponse())
{
Stream Answer = response.GetResponseStream();
// read from stream
StreamReader _Answer = new StreamReader(Answer);
PostResponse = _Answer.ReadToEnd();
}
}
catch (WebException ex)
{
MessageLog("ERROR: Receiving Response : " + ex.ToString() + ":" , "ERROR");
}
}
catch (WebException ex)
{
MessageLog("ERROR Posting " + ex.ToString() + ":" + PostResponse, "ERROR");
}
}
I understand from the error that the server is cutting the connection before I can complete the request. This happens everytime on the server negating thoughts of timeouts I would think.
Having looked around other fourms, I am at a loss , having tried other variations etc the fact that it does work fine with authenication off leads me to think it may be a setting in IIS or something else down the authenication route.
Any insight welcome
I am using twitter streaming API (C#) and getting IOE exception on a regular basis (every 12 hrs or something like that) while Stream reader is trying to read JSON object(readLine). Please look into the exception & the code below. Any help would be highly appreciated. Thank you in advance.
Unable to read data from the transport connection: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection ?failed because connected host has failed to respond.
string userName = "XXXX";
string password = "XXXX";
string url = #"https://stream.twitter.com/1.1/statuses/filter.json";
string parameters = "follow=" + userIds +"&track=" + keywords;
// Request and Response
HttpWebRequest webRequest = null;
HttpWebResponse webResponse = null;
StreamReader streamReader = null;
byte[] byteArray;
// Establishing connection with twitter filter.json
byteArray = Encoding.UTF8.GetBytes(parameters);
webRequest = (HttpWebRequest) WebRequest.Create(url);
webRequest.Credentials = new NetworkCredential(userName, password);
webRequest.Timeout = 100000;
Encoding encode = System.Text.Encoding.GetEncoding("utf-8");
webRequest.Method = "POST";
webRequest.ContentType = "application/x-www-form-urlencoded";
byte[] postData = encode.GetBytes(parameters);
webRequest.ContentLength = postData.Length;
Stream twitterPost = webRequest.GetRequestStream();
twitterPost.Write(postData, 0, postData.Length);
twitterPost.Close();
webResponse = (HttpWebResponse)webRequest.GetResponse();
streamReader = new StreamReader(webResponse.GetResponseStream(), encode);
Stopwatch sw = new Stopwatch();
sw.Start();
while (sw.Elapsed < TimeSpan.FromDays(365))
{
String json = streamReader.ReadLine(); // [The program stop here. throws exception]
if (json == "")
{
continue;
}
Packet dataPacket = new Packet() { json = json, id = id++ };
ThreadPool.QueueUserWorkItem(new WaitCallback(Execute), dataPacket);
}
// Aborting the request and closing the stream
webRequest.Abort();
sw.Stop();
streamReader.Close();
streamReader = null;
webResponse.Close();
webResponse = null;
Sounds like your internet connection dropped or your connection to your router.
In my country most ISP's refresh your ip address daily at midnight, that creates a connection drop for a few seconds, perhaps your ISP is doing something similar?
I am working on a desktop application developed in C# (.NET environment).
This application connects to remote server using HttpWebRequest. If due to any reason my PC is disconnected from the internet and I re-connect it my application always gives request timeout for HttpWebRequest until I restart my whole application and if I again add new thread to my application after network d/c it works fine.
Is there any way to reset my network or anyone can tell me how does it work?
//my code is..
public String request(String add, String post, int time, String reff, int id, int rwtime)
{
try
{
if (rwtime == 0)
{
rwtime = 100000;
}
string result = "";
string location = "";
// Create the web request
HttpWebRequest req = WebRequest.Create(add) as HttpWebRequest;
req.ReadWriteTimeout = rwtime;
req.KeepAlive = true;
req.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip,deflate");
req.Accept = "application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5";
req.ContentType = "application/x-www-form-urlencoded";
req.Timeout = time;
req.Referer = reff;
req.AllowAutoRedirect = false;
req.CookieContainer = statictk.cc[id];
req.PreAuthenticate = true;
if (post != "")
{
req.Method = "POST";
string postData = post;
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] byte1 = encoding.GetBytes(postData);
// Set the content type of the data being posted.
req.ContentType = "application/x-www-form-urlencoded";
// Set the content length of the string being posted.
req.ContentLength = byte1.Length;
Stream newStream = req.GetRequestStream();
newStream.Write(byte1, 0, byte1.Length);
newStream.Close();
}
else
{
req.Method = "GET";
}
// Get response
try
{
HttpWebResponse response = req.GetResponse() as HttpWebResponse;
// Get the response stream
location = response.GetResponseHeader("Location");
if (location == "")
{
Stream responseStream = response.GetResponseStream();
if (response.ContentEncoding.ToLower().Contains("gzip"))
responseStream = new GZipStream(responseStream, CompressionMode.Decompress);
else if (response.ContentEncoding.ToLower().Contains("deflate"))
responseStream = new DeflateStream(responseStream, CompressionMode.Decompress);
StreamReader reader = new StreamReader(responseStream, Encoding.Default);
// Read the whole contents and return as a string
result = reader.ReadToEnd();
}
else
{
result = location;
}
response.Close();
if (result == "") result = "retry";
return result;
}
catch (Exception e)
{
log.store("errorinresponce", e.Message);
if (statictd.status[id] != "removed")
{
return "retry";
}
else
{
return "error";
}
}
}
catch(Exception f)
{
log.store("Networkerrorretry", f.Message);
if (f.Message == "The operation has timed out")
{
return "retry";
}
string ans = MessageBox.Show("There was a Network Error..Wish to Retry ?\nError msg : "+ f.Message, "Title", MessageBoxButtons.YesNo).ToString();
if (ans == "Yes")
return "retry";
else
{
Invoketk.settxt(id, "Not Ready");
return "error";
}
}
}
It sounds like your application is missing some error handling. A disconnect can happen at any time and your application should be able to handle it. Try to surround the network loop with a try-catch statement, and then catch for the different kinds of exceptions. Depending on what exception was thrown, you can then decide if you reconnect to the server silently or if you want to generate an error message.