C# WebResponse Stream losing bytes? - c#

So I have a function like so:
private String SendRequest(String jsonRequest)
{
WebRequest webRequest = WebRequest.Create(_url);
byte[] paramBytes = Encoding.UTF8.GetBytes(jsonRequest);
byte[] responseBytes;
webRequest.Method = "POST";
webRequest.ContentType = "application/json";
webRequest.ContentLength = paramBytes.Length;
webRequest.Headers.Add("X-Transmission-Session-Id", _sessionId);
using (Stream oStream = webRequest.GetRequestStream())
{
oStream.Write(paramBytes, 0, paramBytes.Length);
}
WebResponse webResponse = webRequest.GetResponse();
using (Stream iStream = webResponse.GetResponseStream())
{
responseBytes = new byte[webResponse.ContentLength];
iStream.Read(responseBytes, 0, (int) webResponse.ContentLength);
}
return Encoding.UTF8.GetString(responseBytes);
}
The problem is, at the iStream.Read() stage, some of the bytes are lost. Using wireshark reveals all the bytes are sent to this machine, however .Net is loosing them somewhere along the way. In my current debugging session, for example, where webResponse.ContentLength = 4746 byte[3949] to byte[4745] are all 0's, but they should be populated. As a result, the UTF8 JSON string cuts off early and I can't deserialise my JSON.
I thought the code was pretty clear cut, I can't see where it's going wrong to loose those bytes.
Thanks for any help!

When reading from the stream you can get less bytes than requested.
http://msdn.microsoft.com/en-us/library/system.io.stream.read.aspx
The total number of bytes read into the buffer. This can be less than
the number of bytes requested if that many bytes are not currently
available, or zero (0) if the end of the stream has been reached.
msdn example for WebResponse.GetResponseStream():
http://msdn.microsoft.com/en-us/library/system.net.webresponse.getresponsestream.aspx

I fixed it by using StreamReader instead :)
private String SendRequest(String jsonRequest)
{
WebRequest webRequest = WebRequest.Create(_url);
byte[] paramBytes = Encoding.UTF8.GetBytes(jsonRequest);
String jsonResponse;
webRequest.Method = "POST";
webRequest.ContentType = "application/json";
webRequest.ContentLength = paramBytes.Length;
webRequest.Headers.Add("X-Transmission-Session-Id", _sessionId);
using (Stream oStream = webRequest.GetRequestStream())
{
oStream.Write(paramBytes, 0, paramBytes.Length);
oStream.Close();
}
WebResponse webResponse = webRequest.GetResponse();
using (Stream iStream = webResponse.GetResponseStream())
{
StreamReader reader = new StreamReader(iStream, Encoding.UTF8);
jsonResponse = reader.ReadToEnd();
reader.Close();
iStream.Close();
}
return jsonResponse;
}

Related

Error when using POST method for 2captcha

I Want to solve captcha using 2captcha API.
string Key = "12345678901234567890123456789012";
string Method = "base64";
string DataForPost = $"key={Key}&method={Method}&imginstructions={Imginstructions}";
request.ContentLength = DataForPost.Length;
string responseText = "";
byte[] bytes = Encoding.ASCII.GetBytes(DataForPost);
request.ContentLength = bytes.Length;
using (Stream reqStream = request.GetRequestStream())
{
reqStream.Write(bytes, 0, bytes.Length);
reqStream.Close();
}
using (WebResponse resp = request.GetResponse())
{
Stream respStream = resp.GetResponseStream();
using (StreamReader sr = new StreamReader(respStream))
{
responseText = sr.ReadToEnd();
}
}
Imginstruction is base64 string for image and size is about 4KB. When I ran above code, I got error message - "ERROR_ZERO_CAPTCHA_FILESIZE". This error means 'File size under 100bytes', but I cannot understand because file size is about 4kb.
If you have any idea for this problem, please tell to me.

Send an HTTP POST request with C#

I'm try to Send Data Using the WebRequest with POST But my problem is No data has be streamed to the server.
string user = textBox1.Text;
string password = textBox2.Text;
ASCIIEncoding encoding = new ASCIIEncoding();
string postData = "username" + user + "&password" + password;
byte[] data = encoding.GetBytes(postData);
WebRequest request = WebRequest.Create("http://localhost/s/test3.php");
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = data.Length;
Stream stream = request.GetRequestStream();
stream.Write(data, 0, data.Length);
stream.Close();
WebResponse response = request.GetResponse();
stream = response.GetResponseStream();
StreamReader sr99 = new StreamReader(stream);
MessageBox.Show(sr99.ReadToEnd());
sr99.Close();
stream.Close();
here the result
It's because you need to assign your posted parameters with the = equal sign:
byte[] data = Encoding.ASCII.GetBytes(
$"username={user}&password={password}");
WebRequest request = WebRequest.Create("http://localhost/s/test3.php");
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = data.Length;
using (Stream stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
string responseContent = null;
using (WebResponse response = request.GetResponse())
{
using (Stream stream = response.GetResponseStream())
{
using (StreamReader sr99 = new StreamReader(stream))
{
responseContent = sr99.ReadToEnd();
}
}
}
MessageBox.Show(responseContent);
See the username= and &password= in post data formatting.
You can test it on this fiddle.
Edit :
It seems that your PHP script has parameters named diffently than those used in your question.

Error (HttpWebRequest): Bytes to be written to the stream exceed the Content-Length bytes size specified

I can't seem to figure out why I keep getting the following error:
Bytes to be written to the stream exceed the Content-Length bytes size specified.
at the following line:
writeStream.Write(bytes, 0, bytes.Length);
This is on a Windows Forms project. If anyone knows what is going on here I would surely owe you one.
private void Post()
{
HttpWebRequest request = null;
Uri uri = new Uri("xxxxx");
request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
XmlDocument doc = new XmlDocument();
doc.Load("XMLFile1.xml");
request.ContentLength = doc.InnerXml.Length;
using (Stream writeStream = request.GetRequestStream())
{
UTF8Encoding encoding = new UTF8Encoding();
byte[] bytes = encoding.GetBytes(doc.InnerXml);
writeStream.Write(bytes, 0, bytes.Length);
}
string result = string.Empty;
request.ProtocolVersion = System.Net.HttpVersion.Version11;
request.KeepAlive = false;
try
{
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
using (Stream responseStream = response.GetResponseStream())
{
using (System.IO.StreamReader readStream = new System.IO.StreamReader(responseStream, Encoding.UTF8))
{
result = readStream.ReadToEnd();
}
}
}
}
catch (Exception exp)
{
// MessageBox.Show(exp.Message);
}
}
There are three possible options
Fix the ContentLength as described in the answer from #rene
Don't set the ContentLength, the HttpWebRequest is buffering the data, and sets the ContentLength automatically
Set the SendChunked property to true, and don't set the ContentLength. The request is send chunk encoded to the webserver. (needs HTTP 1.1 and has to be supported by the webserver)
Code:
...
request.SendChunked = true;
using (Stream writeStream = request.GetRequestStream())
{ ... }
The Encoded byte array from your InnerXml might be longer as some characters in an UTF8 encoding take up 2 or 3 bytes for a single character.
Change your code as follows:
using (Stream writeStream = request.GetRequestStream())
{
UTF8Encoding encoding = new UTF8Encoding();
byte[] bytes = encoding.GetBytes(doc.InnerXml);
request.ContentLength = bytes.Length;
writeStream.Write(bytes, 0, bytes.Length);
}
To show exactly what is going on, try this in LINQPad:
var s = "é";
s.Length.Dump("string length");
Encoding.UTF8.GetBytes(s).Length.Dump("array length");
This will output:
string length: 1
array length: 2
and now use an e without the apostrophe:
var s = "e";
s.Length.Dump("string length");
Encoding.UTF8.GetBytes(s).Length.Dump("array length");
which will output:
string length: 1
array length: 1
So remember: string length and the number of bytes needed for a specific encoding might differ.

Stream does not support seek operations

I'm trying to POST to a website where the only parameter needed is "description." I believe it has something to do with the way that I am encoding my data. Am I missing something/going about this the wrong way?
string postData = String.Format("description=" + description + "&");
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(url);
wr.Method = WebRequestMethods.Http.Post;
wr.ContentLength = byteArray.Length;
wr.ContentType = "application/x-www-form-urlencoded";
Stream postStream = wr.GetRequestStream();
postStream.Write(byteArray, 0, byteArray.Length);
postStream.Close();
WebResponse response = await wr.GetResponseAsync();
HttpWebResponse webResponse = (HttpWebResponse)response;
using (var stm = response.GetResponseStream())
{
using (var reader = new StreamReader(stm))
{
var content = await reader.ReadToEndAsync();
reader.Close();
stm.Close();
return content;
}
}
The stream you are trying to read apparently doesn't support seeking. You can also verify that programmatically through its CanSeek property.
If you want the same data in a stream that you can seek, consider reading the entirety of your current stream to a byte[] buffer, then constructing a MemoryStream out of that buffer for use with your StreamReader.

How to use WebRequest to POST some data and read response?

Need to have the server make a POST to an API, how do I add POST values to a WebRequest object and how do I send it and get the response (it will be a string) out?
I need to POST TWO values, and sometimes more, I see in these examples where it says string postData = "a string to post"; but how do I let the thing I am POSTing to know that there is multiple form values?
From MSDN
// Create a request using a URL that can receive a post.
WebRequest request = WebRequest.Create ("http://contoso.com/PostAccepter.aspx ");
// Set the Method property of the request to POST.
request.Method = "POST";
// Create POST data and convert it to a byte array.
string postData = "This is a test that posts this string to a Web server.";
byte[] byteArray = Encoding.UTF8.GetBytes (postData);
// Set the ContentType property of the WebRequest.
request.ContentType = "application/x-www-form-urlencoded";
// 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 ();
// 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.
reader.Close ();
dataStream.Close ();
response.Close ();
Take into account that the information must be sent in the format key1=value1&key2=value2
Here's what works for me. I'm sure it can be improved, so feel free to make suggestions or edit to make it better.
const string WEBSERVICE_URL = "http://localhost/projectname/ServiceName.svc/ServiceMethod";
//This string is untested, but I think it's ok.
string jsonData = "{ \"key1\" : \"value1\", \"key2\":\"value2\" }";
try
{
var webRequest = System.Net.WebRequest.Create(WEBSERVICE_URL);
if (webRequest != null)
{
webRequest.Method = "POST";
webRequest.Timeout = 20000;
webRequest.ContentType = "application/json";
using (System.IO.Stream s = webRequest.GetRequestStream())
{
using (System.IO.StreamWriter sw = new System.IO.StreamWriter(s))
sw.Write(jsonData);
}
using (System.IO.Stream s = webRequest.GetResponse().GetResponseStream())
{
using (System.IO.StreamReader sr = new System.IO.StreamReader(s))
{
var jsonResponse = sr.ReadToEnd();
System.Diagnostics.Debug.WriteLine(String.Format("Response: {0}", jsonResponse));
}
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.ToString());
}
Here's an example of posting to a web service using the HttpWebRequest and HttpWebResponse objects.
StringBuilder sb = new StringBuilder();
string query = "?q=" + latitude + "%2C" + longitude + "&format=xml&key=xxxxxxxxxxxxxxxxxxxxxxxx";
string weatherservice = "http://api.worldweatheronline.com/free/v1/marine.ashx" + query;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(weatherservice);
request.Referer = "http://www.yourdomain.com";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream stream = response.GetResponseStream();
StreamReader reader = new StreamReader(stream);
Char[] readBuffer = new Char[256];
int count = reader.Read(readBuffer, 0, 256);
while (count > 0)
{
String output = new String(readBuffer, 0, count);
sb.Append(output);
count = reader.Read(readBuffer, 0, 256);
}
string xml = sb.ToString();
A more powerful and flexible example can be found here: C# File Upload with form fields, cookies and headers
Below is the code that read the data from the text file and sends it to the handler for processing and receive the response data from the handler and read it and store the data in the string builder class
//Get the data from text file that needs to be sent.
FileStream fileStream = new FileStream(#"G:\Papertest.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite);
byte[] buffer = new byte[fileStream.Length];
int count = fileStream.Read(buffer, 0, buffer.Length);
//This is a handler would recieve the data and process it and sends back response.
WebRequest myWebRequest = WebRequest.Create(#"http://localhost/Provider/ProcessorHandler.ashx");
myWebRequest.ContentLength = buffer.Length;
myWebRequest.ContentType = "application/octet-stream";
myWebRequest.Method = "POST";
// get the stream object that holds request stream.
Stream stream = myWebRequest.GetRequestStream();
stream.Write(buffer, 0, buffer.Length);
stream.Close();
//Sends a web request and wait for response.
try
{
WebResponse webResponse = myWebRequest.GetResponse();
//get Stream Data from the response
Stream respData = webResponse.GetResponseStream();
//read the response from stream.
StreamReader streamReader = new StreamReader(respData);
string name;
StringBuilder str = new StringBuilder();
while ((name = streamReader.ReadLine()) != null)
{
str.Append(name); // Add to stringbuider when response contains multple lines data
}
}
catch (Exception ex)
{
throw ex;
}

Categories

Resources