HttpWebRequest partially fails to get data - c#

I have this code, calling this sample API call of the game Guild Wars 2
HttpWebRequest request = HttpWebRequest.Create("https://api.guildwars2.com/v1/events.json?world_id=1001") as HttpWebRequest;
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
byte[] bytes = new byte[response.ContentLength];
Stream stream = response.GetResponseStream();
stream.Read(bytes, 0, bytes.Length);
string result = Encoding.Default.GetString(bytes);
It is a sample call to the official Guild Wars 2 API and is supposed to return a list of events and their status in JSON format.
If you call the address in a browser and paste the data into a text editor, it gives a correct JSON string, of a little more than 300 kb.
However, when called by this code and, looking at the resulting byte array, the first 3800-3900 bytes are correctly filled (the number varies slightly from call to call), but the rest is all zero.
The response.ContentLength indicates the correct length of the stream, a little more than 300k, and testing with stream.ReadByte() tells me the stream does deliver those 300k, it's just zeroes after that 3850 byte mark.
Is there an error in my code, or what could cause this problem? Could I call the API in another way to get the correct, full response?

The Read operation on a stream returns the number of bytes actually read. You should keep calling stream.Read() until it returns 0. The data simply has not arrived yet.
The reason Read won't block is that some applications may already begin processing the partial data.
You could use the following code:
HttpWebRequest request = HttpWebRequest.Create("https://api.guildwars2.com/v1/events.json?world_id=1001") as HttpWebRequest;
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
byte[] bytes;
using (Stream stream = response.GetResponseStream())
using (MemoryStream buffer = new MemoryStream((int)response.ContentLength))
{
byte[] chunk = new byte[4096];
int bytesRead;
while ((bytesRead = stream.Read(chunk, 0, chunk.Length)) > 0)
{
buffer.Write(chunk, 0, bytesRead);
}
bytes = buffer.ToArray();
}

Related

C# Stream.CanSeek property, This Stream Doesn't Support Seeking

Me and my friend are trying to send http request that we received from the client
listener.Prefixes.Add("http://localhost:3294/discord/");
listener.Start();
Console.WriteLine("Listening...");
HttpListenerContext context = listener.GetContext();
Stream body = context.Request.InputStream;
Encoding encoding = context.Request.ContentEncoding;
StreamReader reader = new StreamReader(body, encoding);
if (body != null)
{
byte[] buffer = new byte[body.Length];
body.Read(buffer, 0, (int)body.Length);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://discord.com/api/webhooks/818198824439004692/jfe2zN93Ca0VOVry0uIBe6xvmx74tYP9QdaEFH--sDMSscKXcgxAYvlu3RSYwb32oZra");
request.Method = "POST";
request.ContentType = context.Response.ContentType;
request.ContentLength = body.Length;
Stream newStream = request.GetRequestStream();
newStream.Write(buffer, 0, buffer.Length);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
}
but I am getting an error System.NotSupportedException: 'This stream does not support seek operations.' when I try accessing body.Length
and I noticed there is CanSeek property in Stream class but it is has only get.
Is there a way to fix this?
You can't change a non-seekable stream to magically become seekable - in this case, the stream is the set of bytes arriving over the network (perhaps after some TLS/etc work). If you need the data to be seekable, you'll need to buffer (copy) it somewhere else (often a MemoryStream), and seek on that. The preferred option, however, is usually to remove the need to seek the data in the first place.

HttpWebRequest not downloading file correctly

I can't use WebClient, before anyone suggests that because it makes my legit application seem like a virus to McAfee. So please don't suggest that.
I have a binary.txt file stored on my server. It is approximately 1,240kb. However, HttpWebRequest downloads random amounts from 1,300kb to 1,700kb.
HttpWebRequest httpRequest = (HttpWebRequest)
WebRequest.Create("http://deviantsmc.com/binary.txt");
httpRequest.Method = WebRequestMethods.Http.Get;
HttpWebResponse httpResponse = (HttpWebResponse)httpRequest.GetResponse();
Stream httpResponseStream = httpResponse.GetResponseStream();
byte[] buffer = new byte[1240];
int bytesRead = 0;
StringBuilder sb = new StringBuilder();
//FileStream fileStream = File.Create(#"tcontent.txt");
while ((bytesRead = httpResponseStream.Read(buffer, 0, 1240)) != 0)
{
sb.Append(Encoding.ASCII.GetString(buffer));
//fileStream.Write(buffer, 0, bytesRead);
}
File.WriteAllText(#"tcontent1.txt", sb.ToString());
(The contents of the binary.txt file on the server are in ASCII, therefore I get the Encoding string to ASCII as well).
This is how I encoded that text file (on that server)
My file is basically this:
byte[] bytes = File.ReadAllBytes("binary.txt");
String encBytes = Encoding.ASCII.GetString(bytes);
File.WriteAllText(file("binary.txt"), encBytes);
I contacted the AV company about the WebDownloader being seen as some malicious import in C#, but they didn't get back to me, so I'm forced to use HttpWebRequest.
If your only goal is to fetch that binary and write it to disk you can simply copy the stream to a file with the CopyTo method that exists on a Stream object.
Your file looks like a broken zip file btw, given the first characters that are PK, and is used in the zip specificaton.
From wikipedia:
Viewed as an ASCII string this reads "PK", the initials of the inventor Phil Katz. Thus, when a .ZIP file is viewed in a text editor the first two bytes of the file are usually "PK".
I used 7-zip to open your file as the Windows default didn't accept it as a valid file. It contains a manifest.mf file but the content itself seems missing. the file itself has a size of 1.269.519 bytes.
HttpWebRequest httpRequest = (HttpWebRequest)
WebRequest.Create("http://deviantsmc.com/binary.txt");
httpRequest.Method = WebRequestMethods.Http.Get;
HttpWebResponse httpResponse = (HttpWebResponse)httpRequest.GetResponse();
Stream httpResponseStream = httpResponse.GetResponseStream();
// create and open a FileStream, using calls dispose when done
using(var fs= File.Create(#"c:\temp\bin.7z"))
{
// Copy all bytes from the responsestream to the filestream
httpResponseStream.CopyTo(fs);
}
I think you should write the entire binary data to the local file, instead of encoding it segmentally, you can try this:
HttpWebRequest httpRequest = (HttpWebRequest)
WebRequest.Create("http://deviantsmc.com/binary.txt");
httpRequest.Method = WebRequestMethods.Http.Get;
HttpWebResponse httpResponse = (HttpWebResponse)httpRequest.GetResponse();
Stream httpResponseStream = httpResponse.GetResponseStream();
using (BinaryReader responseReader = new BinaryReader(httpResponseStream.GetResponseStream()))
{
byte[] bytes = responseReader.ReadBytes((int)response.ContentLength);
using (BinaryWriter sw = new BinaryWriter(File.OpenWrite("tcontent1.txt")))
{
sw.Write(bytes);
sw.Flush();
sw.Close();
}
}
Hope this can help

HttpWebRequest needs to wait 5 seconds to work properly in PUT method

I am trying to use an API and I don't have any problems with GET and POST but PUT isn't working. I tried with a lot of different examples and finally by chance I discovered that waiting more that 5 seconds (with 5000ms it is not working and with 5100ms it does) it starts working properly. But why is that happening? And how can I avoid this? 5 seconds for each registry update is to much waiting and I really don't understand why POST works well without waiting and PUT needs 5 seconds to work.
Here I put the method that I am using with the Thread.Sleep(5100). As I said without this line when I make WebResponse response = request.GetResponse(); gives me an error.
public void call(string url, object jsonObj)
{
try
{
// Create a request using a URL that can receive a post.
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(urlSplio);
// Create POST data and convert it to a byte array.
request.Method = "PUT";
// Set the ContentType property of the WebRequest.
request.ContentType = "application/json";
request.Credentials = new NetworkCredential(WebConfigurationManager.AppSettings["User"], "WebConfigurationManager.AppSettings["Key"]");
string json = JsonConvert.SerializeObject(jsonObj);
byte[] byteArray = Encoding.UTF8.GetBytes(json);
// Set the ContentLength property of the WebRequest.
request.ContentLength = byteArray.Length;
// Get the request stream.
Stream dataStream = request.GetRequestStream();
// Write the data to the request stream.
dataStream.Write(byteArray, 0, byteArray.Length);
// Close the Stream object.
dataStream.Close();
Thread.Sleep(5100);
// Get the response.
WebResponse response = request.GetResponse();
// Display the status.
Console.WriteLine(((HttpWebResponse)response).StatusDescription);
// Get the stream containing content returned by the server.
dataStream = response.GetResponseStream();
// Open the stream using a StreamReader for easy access.
StreamReader reader = new StreamReader(dataStream);
// Read the content.
string responseFromServer = reader.ReadToEnd();
// Display the content.
Console.WriteLine(responseFromServer);
// Clean up the streams.
dataStream.Close();
response.Close();
}
catch (Exception ex)
{
}
}
I think you might want to rewrite the response stream code
Take a look at this walkthrough on MS MS walkthrough
private byte[] GetURLContents(string url)
{
// The downloaded resource ends up in the variable named content.
var content = new MemoryStream();
// Initialize an HttpWebRequest for the current URL.
var webReq = (HttpWebRequest)WebRequest.Create(url);
// Send the request to the Internet resource and wait for
// the response.
// Note: you can't use HttpWebRequest.GetResponse in a Windows Store app.
using (WebResponse response = webReq.GetResponse())
{
// Get the data stream that is associated with the specified URL.
using (Stream responseStream = response.GetResponseStream())
{
// Read the bytes in responseStream and copy them to content.
responseStream.CopyTo(content);
}
}
// Return the result as a byte array.
return content.ToArray();
}

Making Synchronous xmlhttp request in code behind

I am attempting to send XML to a URL and read the response, but the response is coming back empty every time. I think this is because its being processed Asynchronously and so the receiving code hasn't had a chance to complete by the time I read the response. In Javascrpt I would use
xmlhttp.Open("POST", url, false);
to send a request Synchronously. How can I achieve it in C#?
My code is currently
HttpWebRequest objRequest = (HttpWebRequest)WebRequest.Create(url);
objRequest.Credentials = CredentialCache.DefaultCredentials;
objRequest.Method = "POST";
objRequest.ContentType = "text/xml";
Stream dataStream = objRequest.GetRequestStream();
byte[] bytes = new byte[UpliftJobXMLString.Length * sizeof(char)];
System.Buffer.BlockCopy(UpliftJobXMLString.ToCharArray(), 0, bytes, 0, bytes.Length);
dataStream.Write(bytes, 0, bytes.Length);
dataStream.Close();
HttpWebResponse response = (HttpWebResponse)objRequest.GetResponse();
System.IO.StreamReader sr = new System.IO.StreamReader(response.GetResponseStream());
string respString = System.Web.HttpUtility.HtmlDecode(sr.ReadToEnd()); //always empty
Thanks
I'm fairly certain that this is not an async issue. Have you checked what sr.ReadToEnd() returns before the HtmlDecode?
Furthermore, you should check that the server is returning what you're expecting for it to return. Check the response StatusCode and StatusDescription. If your server is throwing an internal server exception (500) or something similar, the response string you read would come up empty as the content of the response would not be sent by the server in the first place.
I don't think your problem is related to sync/async operations. Your code to convert the string to byte array
byte[] bytes = new byte[UpliftJobXMLString.Length * sizeof(char)];
System.Buffer.BlockCopy(UpliftJobXMLString.ToCharArray(), 0, bytes, 0, bytes.Length);
is similar to Unicode encoding(2 bytes per char).
See the differences among encodings
string UpliftJobXMLString = "abcÜ";
byte[] bytesASCII = Encoding.ASCII.GetBytes(UpliftJobXMLString);
byte[] bytesUTF8 = Encoding.UTF8.GetBytes(UpliftJobXMLString);
byte[] bytesUnicode = Encoding.Unicode.GetBytes(UpliftJobXMLString);
Therefore, either set the content-encoding to unicode or use another encoding. For ex;
objRequest.ContentType = "text/xml; charset=utf-8";

How to get content of httpWebresponse in proper string form?

Sometimes I am getting kind of garbled response from several web sites.
Here is my code:
Stream responseStream = response.GetResponseStream();
buffer = new Byte[256];//
int bytesRead;
while ((bytesRead = responseStream.Read(buffer, 0, buffer.Length)) > 0)
{
outStream.Write(buffer, 0, bytesRead);
//resp=resp+ .UTF8.GetString(buffer, 0, bytesRead);
resp=resp + Encoding.ASCII.GetString(buffer); //resp is string
}
when I request from www.google.co.in I get following characters in resp string:
?\b\0\0\0\0\0??}y?F?????????Z??????{7m???oX?\r?Y???33??d;y????n?0?
How should I overcome this problem? Is it related to encoding?
The response I received was GZip-compressed, so I just decompressed the response stream as shown below:
Stream responseStream = response.GetResponseStream();
responseStream = new GZipStream(responseStream, CompressionMode.Decompress);
now one can read the stream using the code I provided above.
#Kalyan Thanks for your help!!!
Refer to How to use the GetResponseStream method in C# and also Usage of HttpWebResponse and HttpWebRequest for getting an idea about reading contents from HttpWebResponse. Hope it will help you.

Categories

Resources