C# WebClient 404 Error Large String - c#

This is wrecking my brain for a while now. The code works fine when I post a smaller XML string. As soon as I add more XML nodes and post, I get the infamous '404 Error'
I'm posting XML data as a string to a Generic Handler in C#.
string strXML = "Large XML Content Here";
WebClient client = new WebClient();
string xmlResult = "";
try
{
xmlResult = client.DownloadString(_workContext.AccountingWebServiceLink
+ "?action=updateprimary&xml="
+ System.Web.HttpUtility.UrlEncode(strXML));
}
catch(Exception e)
{
System.IO.File.AppendAllText(Server.MapPath("~/addressXMLReturnError.txt"),
"Error: " + e.Message + " returnValue = " + xmlResult);
}
I think it might have something to do with the server not accepting large strings?

Finally got it working using suggestions from comments above.
So posting the XML data is the best route for me.
Using code from this SO post > HTTP post XML data in C#
To receive the data on the other side, check out this link > https://code.msdn.microsoft.com/Enviar-datos-por-el-metodo-2e580ace

Related

Flutter-Framework, C# http server and an invalid JSON-Header s Invalid response status code

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.

Should WebClient be used in a using statement?

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?

C# eBay API Upload Return Label

I haven't been able to figure out how to properly upload a label onto eBay using the /post-order/v2/return/{returnId}/file/upload call. I keep getting "The remote server returned an error: (400) Bad Request.".
I believe it may have to do with the image encoding, but I am not entirely certain. I was already able to approve the return with POST /return/{returnId}/decide but the next step in uploading is the problem. I have the image data saved as a base 64 string in a database. I know the data is good, because in other calls I am able to transform that base 64 string into an image in my application. So the data from the image isn't in question. The thing is on http://developer.ebay.com/Devzone/post-order/post-order_v2_return-returnId_file_upload__post.html#samplesellerlabel it states that the image data should be "base64-encoded binary representation of the file".
So is it possible that the data I received when grabbing the image with Convert.ToBase64String(imageBytes) is not what I actually need? There are little to no examples on how to do this particular call in C# and I've tried so many things. I've checked the JSON syntax and it looks to be correct. (I've removed a large portion of the string as it is too large.)
{"fileName":"5074119065_shippingLabel.jpeg","data":"R0lGODlhCAewBIEAAAAAAP///wAAAAAAACH/C05...zR2On54kkB4nfJYrLFRAAOw==","filePurpose":"LABEL_RELATED"}
I'm fairly convinced that the image data is somehow not formatted correctly, but I'm just not sure. If anyone has any experience with this call I'd appreciate your help. Below is my code and the error comes up on the last line. The headers and the JSON code has worked without any issues on other eBay calls which is also a reason I suspect my problem may have to do with the formatting of the image data.
string url = "https://api.ebay.com/post-order/v2/return/" + returnId + "/file/upload";
var cancelOrderRequest = (HttpWebRequest)WebRequest.Create(url);
cancelOrderRequest.Headers.Add("Authorization", "TOKEN " + authToken);
cancelOrderRequest.ContentType = "application/json";
cancelOrderRequest.Accept = "application/json";
cancelOrderRequest.Headers.Add("X-EBAY-C-MARKETPLACE-ID", "EBAY_US");
cancelOrderRequest.Method = "POST";
string fileName = returnId + "_shippingLabel.jpeg";
using (var streamWriter = new StreamWriter(cancelOrderRequest.GetRequestStream()))
{
string json = "{\"fileName\":\"" + fileName + "\",\"data\":\"" + labelData + "\",\"filePurpose\":\"LABEL_RELATED" + "\"}";
streamWriter.Write(json);
streamWriter.Flush();
streamWriter.Close();
}
var response = (HttpWebResponse)cancelOrderRequest.GetResponse();
Hmm. The eBay documentation appears to be inconsistent. In the top part of the documentation page you linked for the Upload Return File method call, it seems to indicate that the data part of the JSON should be an array of strings, not just a single string.
Payload model
The following lists all fields that could be included in the request.
{ /* UploadFileRequest */
"data": [
string
/* More string nodes here */
],
"fileName": string,
"filePurpose": token
}
But in the JSON sample they show on the same page, the data is clearly a single string like you have it in your code. (Notice the square brackets are missing.)
URL format. See also the non-wrapped version of this URL.
POST https://api.ebay.com/post-order/v2/return/5000124931/file/upload
{
"fileName" : "jasmine.jpeg",
"data" : "SGVyZSBpcyB5b3VyIHJld...YWNraW5nIG51bWJlciBpcyAxMjM0NTY3ODk4NzY1",
"filePurpose" : "ITEM_RELATED"
}
I would try changing it to an array to match the documented payload. I'm guessing the sample is probably wrong here.
Also, I would highly recommend using a JSON serializer like Json.Net rather than hand-rolling your own JSON, as it is very easy to get the formatting wrong, which will just end up giving you more "400 Bad Request" headaches. Instead, try making the JSON by using an anonymous object and then serializing it, like this:
var payload = new
{
fileName = returnId + "_shippingLabel.jpeg",
data = new List<string> { labelData },
filePurpose = "LABEL_RELATED"
};
string json = JsonConvert.SerializeObject(payload);

WebClient Passing Parameters With Space Issue

I want to download string by calling api in which i have to pass some parameters
which contains space like :
String myUrl = AppConstants.BASE_URL + AppConstants.getFileteredList + Name + "," + LastName;
WebClient wc = new WebClient();
Uri uri = new Uri(myUrl,UriKind.Absolute);
wc.DownloadStringAsync(uri);
wc.DownloadStringCompleted += wc_DownloadStringCompleted;
it looks like this
http://demo.com/Api/getFileteredList?data=abc%20xyz,abc%20xyz
but in wc_DownloadStringCompleted , e.result throws and exception like
The remote server returned an error: NotFound.
i have tried "Uri.EscapeUriString" and also tried to implement using "HttpWebRequest" but getting same error.
Please help me out this.
Thank You in advance.
I believe its just a Malformed URL. If you peek myUrl you would notice a missing ? or something probably.
Can you check and port more details in your question.

How to display optional fields in response when using C# WebClient and getting exceptions?

I'm using WebClient to do a POST to a server like so:
string URI = "http://mydomain.com/foo";
string myParameters =
"&token=1234" +
"&text=" + HttpUtility.UrlEncode(someVariable);
using (WebClient wc = new WebClient())
{
try
{
wc.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
string HtmlResult = wc.UploadString(URI, myParameters);
}
catch (WebException e)
{
return e.Message;
}
}
I sometimes can get exceptions thrown due to HTTP 403 (forbidden). In those cases, I want to know the exact reason. Digging into the service I'm calling into, it is documneted that it will optionally return an errorDetail field like so:
"code": 403,
"errorType": "not_authorized",
"errorDetail": "Can reply on a checkin at most once."
However, when I'm stepping through the code in Visual Studio, I don't see how I can get the errorDetail field. It doesn't apepar to be part of the WebException.
Is there a way to get it so I could display is something like:
return e.Message + " -- " + e.errorDetail
?
errorDetail is not part of the HTTP specification so WebClient does not know about it. For the same reason you will not find it anywhere in the BCL.
What you probably want is the response body so you can parse it (maybe as JSON? Your data looks like it).
You can get the response object from WebException.Response. Read it just like you normally would read a response.
Be aware that this property might be null if there is no response (due to network error, for example).

Categories

Resources