I am currently developing in Unity (in particular using C#) and I'm stuck with HttpWebRequest - HttpWebResponse random timeouts.
I have some methods that send a POST request to a server I host on my local machine (XAMPP) to use various php scripts which are going to fetch informations from MySQL Database (hosted with XAMPP) and give back those info in JSON format.
Then I handle these JSON informations with my C# scripts.
The problem is that when I run the first test all is good:I can get the JSON data from my Server and show it in the Debug Console.
When I run the second test,a WebException is raised with error:
WebException - The request timed out
After that second test,if I run again and again,the problem keeps presenting in a random way.
I followed all the guidelines I found on the internet on how to setup a webrequest - webresponse properly,in particular I tried to use ServicePoint.DefaultConnectionLimit and ServicePoint.MaxServicePointIdleTime,without any result.
The general structure of my methods (regarding the web request/response part) is something like that:
public void WebMethod(){
string post_url = "http://localhost/service.php?someparam=1&someparam=2";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(post_url);
request.Method = "POST";
request.KeepAlive = false;
request.Timeout = 5000;
request.Proxy = null;
string Response = "";
try
{
using (HttpWebResponse resp = request.GetResponse() as HttpWebResponse)
{
using (Stream objStream = resp.GetResponseStream())
{
using (StreamReader objReader = new StreamReader(objStream, Encoding.UTF8))
{
Response = objReader.ReadToEnd();
objReader.Close();
}
objStream.Flush();
objStream.Close();
}
resp.Close();
}
}catch(WebException e)
{
Debug.Log(e.Message);
}
finally
{
request.Abort();
}
//tried this one after reading some related answers here on StackOverflow,without results
//GC.Collect();
Debug.Log("SERVER RESPONSE:" + Response);
//Response Handling
}
I know that it may be something related to a wrong abort on the HttpWebRequest / Response or maybe related to the HTTP 1.1 connections limit,but I can't figure out any solution at the moment.
Any help is appreciated.
Related
I'm trying to get the order book from GDAX (link to documentation of the call) but when doing it from the c# executable I always get Error 400 - Bad request.
When taking the actual URL and pasting it into my browser, it works fine.
String URL = "https://api.gdax.com/products/BTC-USD/book?level=2";
WebRequest request = WebRequest.Create(URL);
WebResponse response = request.GetResponse();
The actual issue with your API call is , the API is expecting a user-agent string while making the request: Below is the code in working condition:
try
{
String URL = "http://api.gdax.com/products/BTC-USD/book?level=2";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
request.UserAgent = ".NET Framework Test Client";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
var encoding = ASCIIEncoding.ASCII;
using (var reader = new System.IO.StreamReader(response.GetResponseStream(), encoding))
{
string responseText = reader.ReadToEnd();
}
}
catch(WebException ex)
{
HttpWebResponse xyz = ex.Response as HttpWebResponse;
var encoding = ASCIIEncoding.ASCII;
using (var reader = new System.IO.StreamReader(xyz.GetResponseStream(), encoding))
{
string responseText = reader.ReadToEnd();
}
}
Basically ProtocolError indicates that you have received the response but there is an error related to protocol, which you can observe, when you read the response content from exception. I have added catch to handle the exception and read ex.Response (which is HttpWebResponse) and could see that the API is asking for user-agent to be suppllied while making the call. I got to see the error as "{"message":"User-Agent header is required."}"
You can ignore the code inside the exception block, I used it only to see what is the actual response message, which contains actual error details
Note: I have boxed WebRequest to HttpWebRequest to have additional http protocol related properties and most importantly "UserAgent" property which is not available with the WebRequest class.
You need to Accept the certificarte, Google for access to a https webrequest.
Like this
I've been working on a project which makes use of an RTC API and forms authentication. I've hit a bit of bizarre behaviour and I just can't figure this one out.
The scenario that has played out to date is that I can successfully run this project locally end to end. That is, this specific piece of code can:
Contact the remote server and successfully authenticate
After authentication I'm able to pass XML to update a ticket in RTC
The problem starts when I publish to our IIS (7.5) server. All works fine right up until the last .GetResponse call which uses a PUT method to pass my XML to update the ticket in RTC. I keep getting 'The operation has timed out'.
I've spent literally days trying to figure this one out doing all manner of things but nothing has proved useful.
As a test I changed the PUT method on the second call to a GET. And it works! If I used a PUT with the .AllowAutoRedirect = false it works in that I get a response back, but then nothing happens on the RTC side so the request is clearly being ignored. I also noticed that the status being returned is marked as 'Found' instead of 'OK'.
Some people thought at this stage perhaps it was a lack of connectivity between the remote server and the web server. This wouldn't be the case as authentication works and this happens against the same server. I have also manually passed the XML / PUT call using the RESTClient on the web server which was accepted fine.
I just can't understand why it works end to end when running locally, but plays up once deployed to IIS?
I tried using log tracing and I'm not entirely sure if I'm getting anything useful from it. It might be totally unrelated but I can see this in the log that is generated on the IIS server:
<EventData>
<Data Name="ContextId">{00000000-0000-0000-12AF-0080000000F8}</Data>
<Data Name="ModuleName">ManagedPipelineHandler</Data>
<Data Name="Notification">128</Data>
<Data Name="HttpStatus">500</Data>
<Data Name="HttpReason">Internal Server Error</Data>
<Data Name="HttpSubStatus">0</Data>
<Data Name="ErrorCode">0</Data>
<Data Name="ConfigExceptionInfo"></Data>
</EventData>
As I say, I'm not sure if this is even related to the problem I'm having, but rather than ignore it I thought I'd share.
Code that forms the call (excuse the standard of coding, it's work in progress and got messy trying out different things to fix this problem)
//Setup webrequest
CookieContainer _cookies = new CookieContainer();
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(getPath);
var test44 = test4.ToString();
request.CookieContainer = _cookies;
request.ContentType = "application/rdf+xml";
request.Accept = "application/rdf+xml";
request.Method = "PUT";
request.AllowAutoRedirect = true;
request.AllowWriteStreamBuffering = true;
request.Timeout = 40000;
byte[] bytes = Encoding.ASCII.GetBytes(test44);
request.ContentLength = bytes.Length;
Stream dataStream = request.GetRequestStream();
dataStream.Write(bytes, 0, bytes.Length);
dataStream.Close();
//Pass request
logger.Info("Made it up to start of RTC request for secure document.");
using (HttpWebResponse getrespn = requestSecureDocument(request, "https://myserver:9100/jazz", "username", "pass", test44))
{
//Stream ReceiveStream = getrespn.GetResponseStream();
// Encoding encode = System.Text.Encoding.GetEncoding("utf-8");
//StreamReader readStream = new StreamReader(ReceiveStream);
//response = readStream.ReadToEnd();
getrespn.Close();
}
The segment of code which interacts with the RTC server (based on the example from: https://nkumar83.wordpress.com/2013/06/13/consuming-rtc-rational-team-concert-oslc-apis-using-c-post-1-authentication/ with my own tweaks):
public static HttpWebResponse requestSecureDocument(HttpWebRequest _requestItem, string _rtcServerURL, string _userName, string _password, string passXml)
{
try
{
//FormBasedAuth Step 1: Request the resource
HttpWebRequest _request = (HttpWebRequest)WebRequest.Create(_requestItem.RequestUri);
_request.CookieContainer = _requestItem.CookieContainer;
//store the response in _docResponse variable
HttpWebResponse _docResponse = (HttpWebResponse)_request.GetResponse();
//HttpStatusCode.OK indicates that the request succeeded
if (_docResponse.StatusCode == HttpStatusCode.OK)
{
//X-com-ibm-team... header signifies form based authentication is being used
string _rtcAuthHeader = _docResponse.Headers["X-com-ibm-team-repository-web-auth-msg"];
if ((_rtcAuthHeader != null) && _rtcAuthHeader.Equals("authrequired"))
{
_docResponse.GetResponseStream().Flush();
_docResponse.Close();
//Prepare form for authentication
HttpWebRequest _formPost = (HttpWebRequest)WebRequest.Create(_rtcServerURL + "/j_security_check");
_formPost.Method = "POST";
_formPost.Timeout = 30000;
_formPost.CookieContainer = _request.CookieContainer;
_formPost.Accept = "text/xml";
_formPost.ContentType = "application/x-www-form-urlencoded";
string _authString = "j_username=" + _userName + "&j_password=" + _password;
Byte[] _outBuffer = Encoding.UTF8.GetBytes(_authString);
_formPost.ContentLength = _outBuffer.Length;
Stream _str = _formPost.GetRequestStream();
_str.Write(_outBuffer, 0, _outBuffer.Length);
_str.Close();
//FormBasedAuth Step 2: Submit the login form and get response
HttpWebResponse _formResponse = (HttpWebResponse)_formPost.GetResponse();
_rtcAuthHeader = _formResponse.Headers["X-com.ibm-team.repository-web-auth-msg"];
//Check if auth failed
if ((_rtcAuthHeader != null) && _rtcAuthHeader.Equals("authfailed"))
{
//auth fialed
var fail = "";
}
else
{
//login successful
//FormBasedAuth Step 3: Resend the request for the protected resource
_formResponse.GetResponseStream().Flush();
_formResponse.Close();
using (HttpWebResponse getresp = (HttpWebResponse)_requestItem.GetResponse()) *** THIS IS TH LINE WHICH THROWS THE EXCEPTION ***
{
return getresp;
}
}
}
}
return _docResponse;
}
catch (WebException e)
{
var filePath = AppDomain.CurrentDomain.GetData("DataDirectory") + #"/trapA.xml";
using (StreamWriter writer = new StreamWriter(filePath, true))
{
writer.WriteLine("Message: Failed to trigger getresponse successfully: " + e);
}
}
return null;
}
Hope someone out there can help :o)
Well I'm pleased to say I've finally got to the bottom of this one. Turns out the problem wasn't anything to do with IIS and does actually work when published 'if' I'm not using the RTC client to make updates to a ticket.
The short story is that our RTC client uses a custom script to post out to our web api. However the RTC client appears to put a record lock on the ticket your trying to update which is persisted until a response from our API is provided. Of course this can't happen because part of the response is to confirm if the update was successful which can't happen due to the lock made by the RTC client.
The solution was to get the call in from RTC closed as quickly as possible. So the segment of code which authenticates and calls back out to RTC to make updates is now wrapped around with some new code to create a new thread. This has allowed the connection to be closed in about 5 seconds, all the while our app continues to make the necessary calls to complete the transaction.
Thread t = new Thread(() = > {
//code here
}
I have one Windows Handheld device application on .Net framework 3.5 which has the requirement of accessing a REST API. The REST API gives me JSON output which I am going to process later. I have the following code for that:-
HttpWebRequest webRequest;
string result = String.Empty;
try
{
webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.Method = "POST";
webRequest.KeepAlive = false;
webRequest.ContentType = "application/x-www-form-urlencoded";
using (WebResponse response = webRequest.GetResponse())
{
using (StreamReader streamReader = new StreamReader(response.GetResponseStream()))
{
result = streamReader.ReadToEnd();
}
}
}
catch (Exception ex)
{
result = ex.Message;
}
The url variable is holding the url for the API with some query parameters in it.
For Example "http://www.something.com/Login?id=test&pwd=test".
Now my problem is I dont want to use the query string parameters rather I want to use Request parameters because the above approach does not work every time perfectly. Some times I get an "Unauthorized" error. And also I have one tokenId which I need to send everytime I am calling the API and the token Id is in base64 format.
Can anyone please help me how can I use the Request Parameter feature to send the parameter values?
use the Headers property of your request object.
webRequest.Headers.Add("id", "test");
webRequest.Headers.Add("pwd", "test");
webRequest.Headers.Add("token", myToken);
I am getting The remote server returned an error: (400) Bad Request error while running the following code.
I am trying to upload xml file on the http server.
My xml file contains tag for the username,password and domain and when i am trying to connect is manually i am able to connect it,but using same credentials when i am trying to connect it through this code, i am getting 400 Bad Request error.
Please suggest me how to overcome this issue.
Thanks
`
public static void UploadHttp(string xml)
{
string txtResults = string.Empty;
try
{
string url = "http://my.server.com/upload.aspx ";
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
request.KeepAlive = false;
request.SendChunked = true;
request.AllowAutoRedirect = true;
request.Method = "Post";
request.ContentType = "text/xml";
var encoder = new UTF8Encoding();
var data = encoder.GetBytes(xml);
request.ContentLength = data.Length;
var reqStream = request.GetRequestStream();
reqStream.Write(data, 0, data.Length);
reqStream.Close();
WebResponse response = null;
response = request.GetResponse();
var reader = new StreamReader(response.GetResponseStream());
var str = reader.ReadToEnd();
}
catch (WebException ex)
{
if (ex.Status == WebExceptionStatus.ProtocolError)
{
HttpWebResponse err = ex.Response as HttpWebResponse;
if (err != null)
{
string htmlResponse = new StreamReader(err.GetResponseStream()).ReadToEnd();
txtResults = string.Format("{0} {1}", err.StatusDescription, htmlResponse);
}
}
else
{
}
}
catch (Exception ex)
{
txtResults = ex.ToString();
}
}`
Are you sure you should be using POST not PUT?
POST is usually used with application/x-www-urlencoded formats. If you are using a REST API, you should maybe be using PUT? If you are uploading a file you probably need to use multipart/form-data. Not always, but usually, that is the right thing to do..
Also you don't seem to be using the credentials to log in - you need to use the Credentials property of the HttpWebRequest object to send the username and password.
400 Bad request Error will be thrown due to incorrect authentication entries.
Check if your API URL is correct or wrong. Don't append or prepend spaces.
Verify that your username and password are valid. Please check any spelling mistake(s) while entering.
Note: Mostly due to Incorrect authentication entries due to spell changes will occur 400 Bad request.
What type of authentication do you use?
Send the credentials using the properties Ben said before and setup a cookie handler.
You already allow redirection, check your webserver if any redirection occurs (NTLM auth does for sure). If there is a redirection you need to store the session which is mostly stored in a session cookie.
//use "ASCII" or try with another encoding scheme instead of "UTF8".
using (StreamWriter postStream = new StreamWriter(request.GetRequestStream(), System.Text.Encoding.UTF8))
{
postStream.Write(postData);
postStream.Close();
}
I am making a Http Webrequest to an available site that I can visit fine, but the HTTP Web request keeps timing out. Is there any reason why this code might allow it to timeout when it shouldn't?
I've tried upping the timeout setting, but it still continues to timeout.
Uri CameraUrl = new Uri("http://" + cfg_cameraIps[i]);
HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(CameraUrl);
myRequest.Timeout = 5000;
myRequest.Method = "HEAD";
try
{
HttpWebResponse webresponse;
webresponse = (HttpWebResponse)myRequest.GetResponse();
if (webresponse.StatusCode.ToString() == "OK")
{
continue;
}
You're not closing your web response - if you find that the first couple of requests work, but ones after that don't, then that's the problem. It's trying to reuse the existing connection to the server, but it can't because you haven't closed the response.
Change your code to:
using (HttpWebResponse webresponse = (HttpWebResponse) myRequest.GetResponse())
{
if (webresponse.StatusCode == HttpStatusCode.OK)
{
continue;
}
...
}
and see if that helps.
If it's failing on the very first request to the server, then that's something different. In that case, use Wireshark to see what's going on at the network level.
Note that in the code above I've also removed the string conversion in favour of comparing the status codes directly.