I have the following code in a C# WPF app. This has been working perfectly in testing for a month:
try
{
string zServerName = "http://" + dispenseDetails.dipenseServerCompName + ":8800/Api/";
var options = new RestClientOptions(zServerName);
var client = new RestClient(options);
var request = new RestRequest(endpoint + APIparameter);
request.Method = apiMethod;
Debug.WriteLine(zServerName + endpoint + APIparameter);
request.Method = apiMethod;
if (!getToken)
{
if (string.IsNullOrEmpty(dispenseDetails.curZToken))
{
dispenseDetails.curZToken = getNewToken();
Debug.WriteLine("Got new token: " + dispenseDetails.curZToken);
}
else
{
Debug.WriteLine("Already have token: " + dispenseDetails.curZToken);
}
request.AddHeader("Authorization", "Bearer " + dispenseDetails.curZToken);
}
var response = client.ExecuteAsync(request).Result;
Debug.WriteLine(response);
if (response.ErrorException != null)
{
msgBox.Show(null, "Connection failed. " + response.ResponseStatus);
return "false";
}
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
var JsonString = response.Content;
Debug.WriteLine(JsonString);
return JsonString;
}
else
{
Utility.LogFile("API Fail", response.StatusCode.ToString() + ":" + response.Content, apiMethod + " " + endpoint, "zDispenseServer: " + APIparameter + reqBody, false);
return "false";
}
}
catch (Exception exe)
{
Utility.LogFile(exe.Message, "Critial Error: Cannot contact ZDispense Server", "Api Utility", "RestAPI",false);
return "false";
}
Now I am aware it isn't great code and I'm fixing up on the responses (I'm self taught amateur).
My issue is now when I make this call the comp hangs and waits and gets an answer... 15-> 30 secs later.
I understand I'm not using async/await and this will fix the hang, but it has always worked instantly.
TESTED:
I do exactly the same call (using same user and password and everything) with Postman
Status 200OK
Time 40ms
So postman is wokring as per usual.
Wireshark
I have never used wireshark but installed for this reason.
I tested with Postman and the instant I send the call it appears on Wireshark.
0.03s response time.
Tested with my app/restsharp:
0.03s response time BUT it takes about 15-30 secs to appear in wireshark.
My theory is that the call is fast (eg the call then response) as it shows on WS fast BUT it's like the call sits there and is delayed THEN makes the call...
I have other code and another API which is working perfectly fine using the exact code above but to a different server.
The "fast" server is my own nodejs API
This one is a companies API test software on a computer on my local network (home/personal).
I don't know if that matters but thought to mention it.
Could anyone point me in the right direction?
Am I right in saying if it doesnt appear in WS for 15 secs, that means its... "sitting" in Visual Studio before being sent, and if this is the case.... why??
I have no proxies, no weird interesting stuff.
Fresh install of Vis studio because I tried that in case I had some setting screwing things up.
EDIT:
It hangs at
var response = client.ExecuteAsync(request).Result;
Hang might not be the right word, I know it isnt an AWAIT but it used to pause for 0.5 sec but now it hangs for 15-30 secs
In WPF, you should either make your method async void and await ExecuteAsync or use the latest version with sync methods that were recently brought back. These methods do some advanced stuff with thread scheduling to ensure it doesn't block.
Related
since i'm new to the flutter.io-app-framework and c#-http-sever (request and response), i'm struggling with an error for about two weeks or so.
I'm completly new to JSON.
My problem is an invalid JSON header. To be precise, my Android Studio is saying something like "error: HttpException: Invalid response status code, uri = http://127.0.0.1:2508/user/1".
The error is only occurring when using the app for a http request. My firefox and chrome are doing fine. The result is shown as it should.
In my dart/flutter app, i'm just sending a http get request which does look like the following:
Future<String> getData() async {
var response = await http.get(
Uri.encodeFull("http://127.0.0.1:2508/user/1"),
headers: {"Accept": "text/json"});
this.setState(() {
user = json.decode(response.body);
print(user[0]);
});
return "Success!";
}
My c# server code looks like this:
private void HandleClient(TcpClient client)
{
StreamReader reader = new StreamReader(client.GetStream());
StreamWriter writer = new StreamWriter(client.GetStream());
String request = reader.ReadLine();
if (!String.IsNullOrEmpty(request))
{
Log.WriteLine("\nRequest: \n" + request);
string[] tokens = request.Split(' ');
Log.WriteLine("~~~~~ Tokens ~~~~~");
foreach (String token in tokens)
{
Log.WriteLine("~ " + token);
}
Log.WriteLine("~~~~~~~~~~~~~~~~~~\n");
String[] cmds = tokens[1].Split('/');
String cmd = cmds[1].ToUpper();
String json = "";
switch (cmd)
{
case "USER":
if ((cmds.Length >= 3) && (cmds[2] != ""))
{
json += Tools.toJSON(Data.GetBenutzer(Convert.ToInt16(cmds[2])));
}
break;
default:
break;
}
writer.WriteLine(VERSION + " \n200 OK\nServer: " + NAME + "\nContent-Type: text/json\nAccess-Control-Allow-Origin: *\n");
writer.WriteLine(json);
Log.WriteLine("~~~~~~ Json ~~~~~~\n" +
json + "\n" +
"~~~~~~~~~~~~~~~~~~\n");
writer.Flush();
writer.Close();
writer.Dispose();
}
}
Is anything essential missing in the JSON response?
Maybe you have another inspiring idea that can help me.
First off, I'd highly recommend using a http server package that handles the low level stuff like writing headers for you! Someone has gone to the effort of doing this stuff, verifying that it meets the HTTP RFC, testing it, and then giving it away for free!
If this is for an assignment or to learn http, or you have some other good reason, fair enough. But otherwise, there's almost no point in writing something like this from scratch where you could introduce bugs that are hard to figure out. Not only could you introduce http errors, but you'll have to make sure you do threading properly or you could run into problems when you get more traffic. And you'll save a lot of time because someone else has already figured out the hard stuff, so you can concentrate on making whatever it is you actually want to make.
But for your problem - it appears that the http part of the response isn't formatted quite right because flutter isn't recognizing the 200 response code you're trying to send (and therefore isn't reading it).
It's hard to tell without you actually posting what the http response looks like in full, but I think it's to do with an extra line feed.
You have writer.WriteLine(VERSION + " \n200 OK\nServer: "... but I think it should be writer.WriteLine(VERSION + " 200 OK\nServer: " (assuming version is something like HTTP/1.1).
Also you should be aware that the HTTP protocol actually wants \r\n for line feeds, although all modern servers/clients should be able to support just '\n' as well. But it's always better to follow the protocol specification.
If HttpClient is not supposed to be used in a using statement, see these links:
https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/
http://www.nimaara.com/2016/11/01/beware-of-the-net-httpclient/
So if your not supposed to use HttpClient in a using statement then why do so many examples out there put WebClient in a using statement (including Microsoft); also I have not yet seen an article about not putting WebClient in a using statement? Eventually at the lowest level both WebClient and HttpClient end up at the same place opening a TCP/IP socket. Is it what's in-between that makes WebClient acceptable to put in a using statement?
Note I have a reason for asking this question: I have a client application that runs on WinXP, Win7 full and embedded systems, the code that I use to POST XML to my backend host (CentOS system) looks like this:
void PostXml(string url, string xml, int id) {
try
{
//Console.WriteLine("POST Request: " + xml);
using (WebClient wc = new WebClient())
{
wc.Proxy = null; //DEBUG: testing this to see if it helps webclient post failure after time x
wc.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
Byte[] d = Encoding.ASCII.GetBytes(xml);
//however Async below is better regardless for closing app and non interference with GUI
//Byte[] res = web.UploadData(url, "POST", d); //sychrounous will block until sent and response returned
wc.UploadDataCompleted += new UploadDataCompletedEventHandler(web_UploadDataCompleted);
wc.UploadDataAsync(new Uri(url), "POST", d, id);
}
}
catch (WebException ex)
{
string responseText = "";
using (var reader = new StreamReader(ex.Response.GetResponseStream()))
{
responseText = reader.ReadToEnd();
}
string logMsg = DateTime.Now.ToString("s") + " - PostXml WebClient webexception: " + ex.Message + "\r\n" +
" response: " + responseText + "\r\n\r\n";
File.AppendAllText(SPUClient.frmMain._logFile, logMsg);
}
catch (Exception ex) {
//Console.WriteLine("PostXml Exception: " + ex.Message);
string logMsg = DateTime.Now.ToString("s") + " - PostXml exception: " + ex.Message + "\r\n";
File.AppendAllText(SPUClient.frmMain._logFile, logMsg);
}
}
PostXml is called 2 times every 1 minute, I have 400 clients in the field that run this code above, some of them have run for more than a year with no errors. But we have had a few clients that run this code after running for several weeks, or several months just stop doing the UploadDataAsync( "POST" ) evidently? All we know at this time is we don't get an exception, the POST message does not leave the computer and on my CentOS log file I can see that it never arrived (the domain.net.access.log on CentOS shows all the POST connections from all my clients). Remember this rarely happens some clients have never failed, some run for months / weeks before this happens. Restarting the client application fixes the problem of course. Should I be using WebClient in a using statement could that be the cause of something like this issue or is it something else?
I'd like to connect if my Arduino is available on the network. I'm trying to access the Arduino web server using an HTTP client and processing the JSON answer.
Since ping is not available in UWP what are my options? (see: Article)
One option would be to handle the exception of the HTTP client. But is there any more elegant way to check the connection before requesting the JSON data?
One method might be using the HTTPClient to do a GetAsync() and check the Status code coming out of it.
Depending on your time constraints, you can wait for it to time out naturally or pass a cancellation token to break it sooner than the defaults.
From here https://learn.microsoft.com/en-us/windows/uwp/networking/httpclient (slightly modified):
//Send the GET request asynchronously and retrieve the response as a string.
Windows.Web.Http.HttpResponseMessage httpResponse = new Windows.Web.Http.HttpResponseMessage();
string httpResponseBody = "";
try
{
//Send the GET request
httpResponse = await httpClient.GetAsync(requestUri);
if(httpResponse.IsSuccessStatusCode) { /* Do something with it */ }
else { /* Do fallback here */ }
}
catch (Exception ex)
{
httpResponseBody = "Error: " + ex.HResult.ToString("X") + " Message: " + ex.Message;
}
I'm running into an issue where on the first request, and then randomly over time, my client is getting operation time out, with http time out set to 5 seconds. I have 3 other clients running on other machines that are not failing. This machine is windows xp and a bit slower, but it seems like this is happening too frequently. In these instances the server does not even receive a connection attempt. The below code is run in a loop with a monitor.wait so that it only polls every 10 seconds. I thought at first that I wasn't disposing of the connection properly but it seems like I am. I can't run a debugger on this machine(it's not my machine) so I'm struggling to find the issue. It seems like the client is sometimes too slow to even open a connection.
try
{
Uri targetUri = new Uri(urlFormatted.ToString());
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(targetUri);
request.Method = "GET";
request.Timeout = 10000;
WriteInfo(this.GetType(), "Requesting URL: " + urlFormatted.ToString());
response = (HttpWebResponse)request.GetResponse();
break;
}
catch (System.Net.WebException ex)
{
if (ex.Status == WebExceptionStatus.ProtocolError)
{
response = (HttpWebResponse)ex.Response;
logger.Error("Http request failed with errorcode:" + (int)response.StatusCode);
}
logger.Error("Error connecting to [" + server + "]", ex);
if (ex.InnerException != null)
{
responseString = ex.InnerException.Message;
}
else
{
responseString = ex.ToString();
}
}
if (response != null)
{
try
{
//Response handling
}
catch (Exception ex)
{
//errorhandling
}
finally
{
response.Close();
response.Dispose();
}
}
Is there a way to get more info? It seems like the exception is just saying "the operation has timed out", which doesn't give me a lot to go on. On my debugging machine I can get a connection refused message by shutting down my server, but nothing like this, where the server never receives the request.
Also note: The other machines are all windows 7, and a little beefier. They all have the same .net library installed.
More information:
netstat -a 1 -n -p tcp
does not show the connection at all when it's attempting to connect but gets the operation timed out message. This seems weird. It's like it's not actually attempting the connection. It does show when it establishes correctly.
I am wondering how can I check if the RestSharp request I made failed because the server is down vs something else.
When I shutdown my server I get a status code of "NotFound" but that could be a particular record was not found(which I do on my site if say they try to find a record that might be recently deleted).
How can I figure out the server is actually down?
Edit
here is my code
private readonly RestClient client = new RestClient(GlobalVariables.ApiUrl);
var request = new RestRequest("MyController", Method.POST);
request.AddParameter("UserId", "1");
request.AddParameter("Name", name.Trim());
var asyncHandle = client.ExecuteAsync(request, response =>
{
var status = response.StatusCode;
});
When the server is down, it should not return a "404 NotFound" error.
The most appropriate in this case is HTTP Error 503 - Service unavailable
The Web server (running the Web site) is currently unable to handle
the HTTP request due to a temporary overloading or maintenance of the
server. The implication is that this is a temporary condition which
will be alleviated after some delay. Some servers in this state may
also simply refuse the socket connection, in which case a different
error may be generated because the socket creation timed out.
That way checking that RestResponse.StatusCode is 503 it will tell you that the server is down.
I am having the same issue.
I decided to check for the ContentLength too. At least my webservice always returns ContentLength>0 (even for NotFound occurrences). This seems to work out.
if ( response.StatusCode == System.Net.HttpStatusCode.NotFound &&
response.ContentLength == -1 ){
==> client couldn't connect to webservice
}
In my scenario, I needed to check if anything happened to the connection, e.g. connection time out, can't resolve the host name, etc. So I also added following code:
try
{
var client = new RestClient(_configuration.ServerUrl);
var request = new RestRequest
{
Resource = _configuration.SomeUrl,
Method = Method.POST
};
var response = client.Execute(request);
if (response.ErrorException != null)
{
throw response.ErrorException;
}
}
catch (WebException ex)
{
// TODO: check ex.Status, if it matches one of needed conditions.
}
For more information about WebExceptionStatus Enumeration, please, see following link https://msdn.microsoft.com/en-us/library/system.net.webexceptionstatus(v=vs.110).aspx