I'm stumped - looking for some help if possible....
I use Fiddler a lot to help me write code against remote APIs, have done for ages without any issues. Happy Days!
But, I have hit a problem I just cannot get my head around...
I am making a call to a remote API. When I make the call WITH fiddler running it works perfectly. When I make the very same call WITHOUT fiddler running, the call times out?
This is not just happening on my development machine. The client reported the problem first. And sure enough, when I asked him to install fiddler it works at his end as well!
I just cannot work out why making a call to this API fails only when Fiddler is not running and works when fiddler is running??
Can anyone suggest anything please?
This is my code:
public static SalesForceModel.ClipIdResponse getClipId(string instance_url, string access_token, string clipTitle)
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create(instance_url + "/services/data/v20.0/sobjects/vClip__c");
httpWebRequest.Headers.Add("Authorization", "Bearer " + access_token);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
string json = "{\"Type__c\":\"PowerPoint\"," +
"\"Title__c\":\"" + clipTitle + "\"}";
streamWriter.Write(json);
streamWriter.Flush();
streamWriter.Close();
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
return JsonConvert.DeserializeObject<SalesForceModel.ClipIdResponse>(result);
}
}
}
Typically this behavior indicates that you've failed to properly close the stream returned by the GetResponseStream() function, as described in the HTTPWebRequest section of this blog post.
However, your using statement should be properly disposing of the used StreamReader and that should be closing the underlying stream properly.
Is there any other use of HTTPWebRequest's GetResponseStream() function elsewhere in your app that might not be closing a stream? Is there a change in behavior if you explicitly call httpResponse.Close() after calling the ReadToEnd() method?
Related
I am new to StackOverflow but I heard that there are awesome and helpful people who can help me out. 😉
My mission:
To find a way to make a trade calling the Binance REST API using c#
Without dlls, using my own code (for speed update)
Now I using the Binance.API package but my bot needs to be a bit faster as its speed is not enough.
Also, it would be a great thing to be able to do that without any external sources like dlls. Isn't it? 😎
What I tried:
Success: I can call the public API without problem with "WebRequest" and which there is no need authentication.
WebRequest webrequest = WebRequest.Create("https://api.binance.com/api/v3/ticker/price?symbol=BTCUSDT");
WebResponse Response = webrequest.GetResponse();
StreamReader reader = new StreamReader(Response.GetResponseStream());
MessageBox.Show(reader.ReadToEnd());
Success: I can call the REST API without problem with "WebRequest" and which there is need authentication. BUT only the account information.
string dataQueryString = "recvWindow=15000×tamp=" + Math.Round(Convert.ToDecimal(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds), 0).ToString();
WebRequest webrequest = WebRequest.Create("https://api.binance.com/api/v3/account?" + dataQueryString + "&signature=" + BitConverter.ToString(new HMACSHA256(Encoding.ASCII.GetBytes(tempAPI_Secret)).ComputeHash(Encoding.ASCII.GetBytes(dataQueryString))).Replace("-", string.Empty).ToLower());
webrequest.Method = "GET";
webrequest.Headers.Add("X-MBX-APIKEY", tempAPI_Key);
WebResponse Response = webrequest.GetResponse();
StreamReader reader = new StreamReader(Response.GetResponseStream());
string response = reader.ReadToEnd();
reader.Close();
Response.Close();
!!! THE PROBLEM !!! I can't call the ORDER REST API with "WebRequest" and which there is need authentication. I tried the code below. (It is called the same way as the account information but with the type of POST and of course with the plus parameters needed)
string dataQueryString = "symbol=BTCUSDT&side=SELL&type=LIMIT&quantity=0.00039&price=38878&newOrderRespType=RESULT&recvWindow=15000×tamp=" + Math.Round(Convert.ToDecimal(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds), 0).ToString();
WebRequest webrequest = WebRequest.Create("https://api.binance.com/api/v3/account?" + dataQueryString + "&signature=" + BitConverter.ToString(new HMACSHA256(Encoding.ASCII.GetBytes(tempAPI_Secret)).ComputeHash(Encoding.ASCII.GetBytes(dataQueryString))).Replace("-", string.Empty).ToLower());
webrequest.Method = "POST";
webrequest.Headers.Add("X-MBX-APIKEY", tempAPI_Key);
WebResponse Response = webrequest.GetResponse();
StreamReader reader = new StreamReader(Response.GetResponseStream());
string response = reader.ReadToEnd();
reader.Close();
Response.Close();
The returned ERROR code:
'The remote server returned an error: (400) Bad Request.'
I can't understand why this is not working. (I tried to do the order with exactly these parameters from the web client manually and it was successful)
I checked these possible problems:
I have enough funds on my spot account
I trying to sell more than the minimum trade amount is
There is the official Binance REST API documentation: HERE
I tried to google it but I couldn't find the solution even here.
Thanks to read it and if you could help me I would really appreciate it. 🙏
If something is not clear please ask it, I will answer!
I was literarly doing the same thing you are a few days ago, except I was using python. I'm also glad to see I'm not the only one who likes coding from scratch.
My solution was to leave the url as is https://api.binance.com/api/v3/account and instead of attaching my order parameters symbol=BTCUSD&side=BUY&etc... onto the url I had to instead encode and send that data through the data parameter of python's built in function urllib.request.Request(url, data, headers)
I don't know C# that well so I wouldn't know how to translate my python code to C#, but I did find this doc link that provides an example on how to send data using a POST request. You could also take a look at my question and answer as another example.
I have a code where I am sending the URL request and receiving the response and storing it as a String as
public String GenerateXML(String q)// Here 'q' is the URL
{
// Generating the XML file for reference
// Getting the response in XML format from the URL
Debug.WriteLine("The Http URL after URL encoding :" + q);
try
{
Uri signs1 = new Uri(q);
//Debug.WriteLine("The Requested URL for getting the XML data :" + re);
WebRequest request1 = WebRequest.Create(signs1);
HttpWebResponse response1 = (HttpWebResponse)request1.GetResponse();
//HttpWebResponse response1 = (HttpWebResponse)request1.GetResponse();
Stream receiveStream = response1.GetResponseStream();
StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8);
String ab = readStream.ReadToEnd();// The mentioned error is showing up here.
// Debug.WriteLine("The data :"+a);
//XmlDocument content2 = new XmlDocument();
// content2.LoadXml(ab);
// content2.Save("C:/Users/Administrator/Downloads/direct.xml");
return ab;
}
catch (System.Net.WebException ex)
{
Debug.WriteLine("Exception caught :" + ex);
return null;
}
}
Why is the connection closed by the remote host?
What are the possibilities of getting rid of the error or at least ignore the error and continue with other URL requests? I have included try and catch so as to escape any error and continue functioning with out any stop. Scoured the internet for solution but solutions to this particular problem is pretty much specific. Please any help is appreciated.
Thanks in advance.
I had similar problems with the connection being forcibly closed with different hosts. Seems the issue can be resolved by altering various properties of the WebRequest object.
The following findings were outlined in a blog post by briancaos: An existing connection was forcibly closed by the remote host
The steps mentioned in the the above post include:
Set WebRequest.KeepAlive to False.
Set WebRequest.ProtocolVersion to HttpVersion.Version10.
Set WebRequest.ServicePoint.ConnectionLimit to 1
It indeed work for me, but I haven't tested it on multiple hosts as of yet. However, I seriously suggest reading the post as it goes into way more detail.
In case the link get's broken, here's the Archive.org cached version.
The actual exception is probably an IOException - you would need to catch that exception type as well as WebException. The actual problem may be that your URL is out of date and the system is no longer running a web server, or perhaps, the request needs to be authenticated/needs a header as #L.B suggests.
Also, you are potentially leaking all sorts of resources. You should be wrapping your WebResponse and streams in using statements.
using (var response = (HttpWebResponse)request.GetResponse())
using (var receiveStream = response.GetResponseStream())
using (var reader = new StreamReader(receiveStream))
{
var content = reader.ReadToEnd();
// parse your content, etc.
}
Had the same problem today, So I also wrapped the request in a try/catch with WebException, in my case, adding:
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
Before the webRequest did the trick. Also you should be wrapping your WebResponse and streams in using statements as tvanfosson mentioned.
I hope this helps.
Good day.
I really need help on this issue. I have tried every possible option here.
I use a REST API in an Outlook add-in using C#. The code links outlook items to CRM records, one way. The add-in works 100% fine but after a couple of calls outs i keep on getting the error "The operation has timed out".
When I use the Google Chrome App "Advanced REST Client" I can post the same request 50 times after each other with no time out error.
From within the add-in I use POST, GET and PATCH HttpWebRequest and I get the error for all of them. The error happens at the code line System.IO.Stream os = req.GetRequestStream();
Below is the method:
public static string HttpPatch(string URI, string Parameters)
{
var req = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(URI);
if (GlobalSettings.useproxy.Equals("true"))
{
req.Proxy = WebRequest.DefaultWebProxy;
req.Credentials = new NetworkCredential(GlobalSettings.proxyusername, GlobalSettings.proxypassword, GlobalSettings.proxydomain);
req.Proxy.Credentials = new NetworkCredential(GlobalSettings.proxyusername, GlobalSettings.proxypassword, GlobalSettings.proxydomain);
}
req.Headers.Add("Authorization: OAuth " + GlobalSettings.token.access_token);
req.ContentType = "application/json";
req.Method = "PATCH";
byte[] data = System.Text.Encoding.Unicode.GetBytes(Parameters);
req.ContentLength = data.Length;
using (System.IO.Stream os = req.GetRequestStream())
{
os.Write(data, 0, data.Length);
os.Close();
}
WebResponse resp;
try
{
resp = req.GetResponse();
}
catch (WebException ex)
{
if (ex.Message.Contains("401"))
{
}
}
}
I suspect the problem is that you're not disposing of the WebResponse. That means the connection pool thinks that the connection is still in use, and will wait for the response to be disposed before reusing it for another request. The connection is needed in order to get a request stream, and it won't become available unless the finalizer happens to kick in at a useful time, hence the timeout.
Simply change your code using the response to use a using statement - or in your case, potentially something a little more complicated using a finally block as you're assigning it within a try block. (We can't really see how you're using the response, which makes it hard to give sample code around that. But fundamentally, you need to dispose it.)
I am working on a client that uses a webservice to get some events pushed its way - the webservice is designed so, that upon the client POST'ing a subscribe command, it will send back some events of interest and keep doing so as long as the client stay connected.
When POSTing the command, the service responds (immediately) with an initial answer with these headers
Keep-Alive: timeout=5, max=98
Connection: Keep-Alive
Transfer-Encoding: chunked
and then keeps the connection open until it times out (after 30s, if the client does not send some keep-alive data)
Since it is a mix of POST + having to read the response + keeping the connection open until endOFStream, it appears I have to use HttpWebRequest with BeginGetRequestStream (to POST) and BeginGetResponse to read and act on the response.
My problem is that the BeginGetResponse callback is not called until the input stream is actually closed by the server/service (after 30s), despite AllowReadStreamBuffering being set to false.
The doc have this to say on AllowReadStreamBuffering:
The AllowReadStreamBuffering property affects when the callback from BeginGetResponse method is called. When the AllowReadStreamBuffering property is true, the callback is raised once the entire stream has been downloaded into memory. When the AllowReadStreamBuffering property is false, the callback is raised as soon as the stream is available for reading which may be before all data has arrived.
I've seen a few suggestions that no matter what AllowReadStreamBuffering is set to, HttpWebRequest will not call BeginGetResponse until it's buffer is filled up - but I have not been able to find anything on that in the docs.
Does any one have an idea on how to control this buffering behaviour or maybe suggestion to another approach I should try when dealing with this kind of webservice?
The relevant snippets of the code I currently use, look like this:
public void open()
{
string url = "http://funplaceontheinternet/webservice";
HttpWebRequest request = WebRequest.CreateHttp(url);
request.Method = "POST";
request.Credentials = new NetworkCredential("username", "password");
request.CookieContainer = new CookieContainer();
request.AllowReadStreamBuffering = false;
request.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), request);
}
void GetRequestStreamCallback(IAsyncResult result)
{
Debug.WriteLine("open.GetRequestStreamCallback");
HttpWebRequest webRequest = (HttpWebRequest)result.AsyncState;
// End the stream request operation
Stream postStream = webRequest.EndGetRequestStream(result);
// Create the post data
byte[] byteArray = Encoding.UTF8.GetBytes(_xmlEncodedSubscribeCommand);
// Add the post data to the web request
postStream.Write(byteArray, 0, byteArray.Length);
postStream.Close();
// Start the web request
webRequest.BeginGetResponse(new AsyncCallback(BeginGetResponseCallback), webRequest);
}
void BeginGetResponseCallback(IAsyncResult result)
{
HttpWebRequest request = (HttpWebRequest)result.AsyncState;
HttpWebResponse response = null;
if (request != null)
response = (HttpWebResponse)request.EndGetResponse(result);
else
Debug.WriteLine("request==null :-(");
if (response != null)
{
using (var reader = new StreamReader(response.GetResponseStream()))
{
while (!reader.EndOfStream)
{
string line = reader.ReadLine();
Debug.WriteLine("BeginGetResponseCallback - received: " + line);
}
Debug.WriteLine("BeginGetResponseCallback - reader.EndOfStream");
}
}
else
Debug.WriteLine("response==null :-(");
}
You've mentioned that the service is a web service, but not which platform.
If this is a "normal" web service, then I assume that XML is the transport format.
If so, I suspect the problem may be that this style of communication does not really lend itself to streaming. The web service infrastructure at the server end might not be creating the SOAP envelope and payload until all the data is available. If you wanted to stream like this, you might be better using some custom service at the server end, rather than a web service.
Do you know for sure that the server is really streaming the response? (e.g confirmed with something like wireshark?)
If you really want to use a web service, then I would suggest you complete the request when the first event(s) are available, and don't wait for the timeout. This will still achieve the latency reduction that I assume you are trying to get.
I have been playing with ASP.NET Web API. I am looking to see can I post to a method I have built which simply returns back the object I have POSTED:
On The Accounts Controller:
// POST /api/accounts
public Account Post(Account account)
{
return account;
}
Code Used To Post:
public void PostAccount()
{
// http://local_ip/api/accounts
var uri = string.Format("{0}", webServiceRoot);
var acc = new Account();
acc.AccountID = "8";
acc.AccountName = "Mitchel Cars";
acc.AccountNumber = "600123801";
acc.SubscriptionKey = "2535-8254-8568-1192";
acc.ValidUntil = DateTime.Now;
var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/xml";
request.ContentLength = 800;
XmlSerializer xmlSerializer = new XmlSerializer(typeof(Account));
xmlSerializer.Serialize(request.GetRequestStream(), acc);
var response = (HttpWebResponse)request.GetResponse();
XmlSerializer serializer = new XmlSerializer(typeof(Account));
var newAcc = (Account)serializer.Deserialize(response.GetResponseStream());
}
I have removed any error checking or any boiler plate code to make it easier to read. This is strictly a spike just to under stand to to actually POST. My understanding is that you should write to the GetRequestStream(). All the reading and such seems to work ok but I never here back from the request.GetResponse();
If I do a simple get it works fine. I did see you can use a class called HTTPClient for doing this stuff but I can't use it as I need to get this working for WinForms, Silverlight and Windows Phone all based on .Net 3.5
Any help pushing POCO's to the server would be a great help, cheers!
ADDITIONAL INFO:
Currently I get no error, the test app just hangs.
If I turn off the WebAPI project I get a server not found response.
I have not changed any routes or any of that.
Gets to the same controller work.
You will need to close the response stream. Most examples I see also show setting the content length. You may be better to serialize to a memory stream and then use the length of that stream as the Content-Length. Unfortunately in .net 3.5 there is no CopyStream so you may have to write that yourself.
If you want to use the HttpClient, you can install the download the REST starter Kit. and use the DLLs as external DLLs
http://forums.asp.net/t/1680252.aspx/1