Rather than add on to my question here, I'm adding a new one as, once I looked at my code with my X-Ray vision goggles attached, I don't grok it.
I don't even remember where I got this code, but it's an adaptation of an example I found somewhere. Yet it doesn't seem that the data is even being sent to the server. To be specific, this code:
public static string SendXMLFile(string xmlFilepath, string uri)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.KeepAlive = false;
request.ProtocolVersion = HttpVersion.Version10;
request.Method = "POST";
StringBuilder sb = new StringBuilder();
using (StreamReader sr = new StreamReader(xmlFilepath))
{
String line;
while ((line = sr.ReadLine()) != null)
{
// test to see if it's finding any lines
//MessageBox.Show(line); <= works fine
sb.AppendLine(line);
}
byte[] postBytes = Encoding.UTF8.GetBytes(sb.ToString());
request.ContentLength = postBytes.Length;
// Did the sb get into the byte array?
//MessageBox.Show(request.ContentLength.ToString()); <= shows "112" (seems right)
request.KeepAlive = false;
request.ContentType = "application/xml";
try
{
Stream requestStream = request.GetRequestStream();
// now test this: MessageBox.Show() below causing exception? See https://stackoverflow.com/questions/22358231/why-is-the-httpwebrequest-body-val-null-after-crossing-the-rubicon
//MessageBox.Show(string.Format("requestStream length is {0}", requestStream.Length.ToString()));
requestStream.Write(postBytes, 0, postBytes.Length);
MessageBox.Show(string.Format("requestStream length is {0}", requestStream.Length.ToString()));
requestStream.Close();
using (var response = (HttpWebResponse)request.GetResponse())
{
return response.ToString();
}
}
catch (Exception ex)
{
MessageBox.Show("SendXMLFile exception " + ex.Message);
request.Abort();
return string.Empty;
}
}
}
...seems to be doing this:
0) Reads the contents of the file at xmlFilepath and puts it into a StreamReader ("sr")
1) A StringBuilder ("sb") is populated with the contents of the StreamReader
2) The contents of the StringBuilder are put into an array of Bytes ("postBytes")
- then here comes the weird part (or so it seems to me, after analyzing the code more closely):
3) The contents of the array of bytes are written to a Stream ("requestStream")
4) The Stream is closed (???)
5) The HttpWebRequest ("request") attempts to return a HttpWebResponse by calling GetResponse()
but what does "request" contain? The contents (of the StreamReader => StringBuilder => Array of Bytes => Stream) are never assigned to it! It seems as if the Stream exists for the sole purpose of writing lines of code, heating up the processor, and slowing down the operation!
Is this code nonsensical, or am I just not grokking it?
GetRequestStream() returns a stream that forwards writes through the HttpWebRequest to the network.
Your code is unnecessarily long, but correct.
However, response.ToString() is wrong; you want to read response.GetResponseStream() with a StreamReader.
Related
I have read other similar questions and tried the solutions from those questions, but since that did not work, hence I am posting this here.
When I send POST request below, it fails with the following error message:
System.Net.ProtocolViolationException: You must write ContentLength bytes to the request stream before calling [Begin]GetResponse.
at System.Net.HttpWebRequest.GetResponse()
....
....
My GET requests for other URL end points are working fine, I am only having this issue while issuing a POST request. Also, I have already set the ContentLength in the code appropriately. I am still unable to send the POST request. Thoughts?
public void TestSubmitJobWithParams1()
{
const string RestActionPath = "URL_GOES_HERE";
// if you have multipe parameters seperate them with teh '&' delimeter.
var postData = HttpUtility.UrlEncode("MaxNumberOfRowsPerSFSTask") + "=" + HttpUtility.UrlEncode("3000");
var request = (HttpWebRequest)WebRequest.Create(RestActionPath);
request.Method = "POST";
request.Credentials = CredentialCache.DefaultCredentials;
request.PreAuthenticate = true;
request.ContentLength = 0;
request.Timeout = 150000;
request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.BypassCache);
request.ContentType = "application/x-www-form-urlencoded";
byte[] bytes = Encoding.ASCII.GetBytes(postData);
request.ContentLength = bytes.Length;
Stream newStream = request.GetRequestStream();
newStream.Write(bytes, 0, bytes.Length);
string output = string.Empty;
try
{
using (var response = request.GetResponse())
{
using (var stream = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding(1252)))
{
output = stream.ReadToEnd();
}
}
}
catch (WebException ex)
{
if (ex.Status == WebExceptionStatus.ProtocolError)
{
using (var stream = new StreamReader(ex.Response.GetResponseStream()))
{
output = stream.ReadToEnd();
}
}
else if (ex.Status == WebExceptionStatus.Timeout)
{
output = "Request timeout is expired.";
}
}
catch (ProtocolViolationException e)
{
Console.WriteLine(e);
}
Console.WriteLine(output);
Console.ReadLine();
}
A few things:
Firstly, you don't need to set ContentLength directly - just leave it out (defaults to -1). You're actually calling it twice, so remove both calls.
Also, you need to call Close() on the stream before calling GetResponse()
Stream newStream = request.GetRequestStream();
newStream.Write(bytes, 0, bytes.Length);
newStream.Close();
Alternatively, you could have it within a using statement, which handles the closing and disposal for you):
using (var newStream = request.GetRequestStream())
{
newStream.Write(bytes, 0, bytes.Length);
}
You also don't technically need to use HttpUtility.UrlEncode() for the postData since there's nothing in your string that would violate a Url's integrity. Just do:
string postData = "MaxNumberOfRowsPerSFSTask=3000");
Let me know if that solves it for you.
For a more thorough rundown, check this out: http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.getresponse.aspx
Specifically, the section about ProtocolViolationException and also where it says:
When using the POST method, you must get the request stream, write the data to be posted, and close the stream. This method blocks waiting for content to post; if there is no time-out set and you do not provide content, the calling thread blocks indefinitely.
I got code, that sending GET request and recieves answer in stream. I read stream with streamreader to end. Here is code:
HttpWebRequest requestGet = (HttpWebRequest)WebRequest.Create(url);
requestGet.Method = "GET";
requestGet.Timeout = 5000;
HttpWebResponse responseGet = (HttpWebResponse)requestGet.GetResponse();
StreamReader reader = new StreamReader(responseGet.GetResponseStream());
StringBuilder output = new StringBuilder();
output.Append(reader.ReadToEnd());
responseGet.Close();
But i dont like that program is waiting until all data recieved before starting working with response. It would be great if i can do it like this(pseudocode):
//here sending GET request
do
{
response.append(streamPart recieved);
//here work with response
} while (stream not ended)
I tried streamReader.Read(char[], int32_1, int32_2), but i cant specify int32_2, becouse i dont know how many symbols i recieved. And if i use ReadToEnd - it waits for all response to load.
Read takes a char[] buffer and returns the number of characters read from the stream.
Here's an example of how to read the response in chunks:
public static void Main(string[] args)
{
var req = WebRequest.Create("http://www.google.com");
req.Method = "GET";
req.Timeout = 5000;
using (var response = req.GetResponse())
using (var reader = new StreamReader(response.GetResponseStream()))
{
char[] buffer = new char[1024];
int read = 0;
int i = 0;
do
{
read = reader.Read(buffer, 0, buffer.Length);
Console.WriteLine("{0}: Read {1} bytes", i++, read);
Console.WriteLine("'{0}'", new String(buffer, 0, read));
Console.WriteLine();
} while(!reader.EndOfStream);
}
}
I didn't see any extraneous white space or repeated data.
I am using below code to send a byte array to a site. Why this code is not throwing an exception even when there is no internet connection?.Even when no connection is there I am able to get stream and able to write to it.I expect it to throw an exception at Stream postStream = request1.EndGetRequestStream(result).Anyone got any idea why its behaving like this.
private void UploadHttpFile()
{
HttpWebRequest request = WebRequest.CreateHttp(new Uri(myUrl));
request.ContentType = string.Format("multipart/form-data; boundary={0}", boundary);
request.UserAgent = "Mozilla/4.0 (Windows; U; Windows Vista;)";
request.Method = "POST";
request.UseDefaultCredentials = true;
request.BeginGetRequestStream(GetStream, request);
}
private void GetStream(IAsyncResult result)
{
try
{
HttpWebRequest request1 = (HttpWebRequest)result.AsyncState;
using (Stream postStream = request1.EndGetRequestStream(result))
{
int len = postBody.Length;
len += mainBody.Length;
len += endBody.Length;
byte[] postArray = new byte[len + 1];
Encoding.UTF8.GetBytes(postBody.ToString()).CopyTo(postArray, 0);
Encoding.UTF8.GetBytes(mainBody).CopyTo(postArray, postBody.Length);
Encoding.UTF8.GetBytes(endBody).CopyTo(postArray, postBody.Length + mainBody.Length);
postStream.Write(postArray, 0, postArray.Length);
}
}
I expect it's buffering everything until you're done writing, at which point it will be able to use the content length immediately. If you set:
request.AllowWriteStreamBuffering = false;
then I suspect it will fail at least when you write to the stream.
Btw, your calculation of the required length for postArray appears to be assuming one byte per character, which won't always be the case... and you're calling ToString on postBody which looks like it's redundant. I'm not sure why you're trying to write in a single call anyway... either you could call Write three times:
byte[] postBodyBytes = Encoding.UTF8.GetBytes(postBody);
postStream.Write(postBodyBytes, 0, postBodyBytes.Length);
// etc
or (preferrably) just use a StreamWriter:
using (Stream postStream = request1.EndGetRequestStream(result))
{
using (StreamWriter writer = new StreamWriter(postStream)
{
writer.Write(postBody);
writer.Write(mainBody);
writer.Write(endBody);
}
}
It's also unclear why you've added 1 to the required length when initializing postArray. Are you trying to send an extra "0" byte at the end of the data?
how can i upload a large string (in my case XML with BLOB) with POST without getting Timeout with GetResponse?
Changing the timeout helps, but this isn't really a solution.
If the Server is really death or the POST was interrupted i have to wait for the extrem large timeout.
Any Idea?
HttpWebRequest webRequest = null;
string response = "";
byte[] bytes = Encoding.UTF8.GetBytes(xml);
try
{
webRequest = (HttpWebRequest)WebRequest.Create("http://" + this.host + ":" + this.port);
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.Method = "POST";
webRequest.Timeout = 5000;
webRequest.ContentLength = bytes.Length;
using (Stream requeststream = webRequest.GetRequestStream())
{
requeststream.Write(bytes, 0, bytes.Length);
requeststream.Close();
}
using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse())
{
using (StreamReader sr = new StreamReader(webResponse.GetResponseStream()))
{
response = sr.ReadToEnd().Trim();
sr.Close();
}
webResponse.Close();
}
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
return response;
Yes, this is pretty much expected http behaviour.
Options:
have a large timeout (you've already done this), and accept that it could take a long time to legitimately time out (as opposed to taking a while because of bandwidth)
maybe you can apply gzip on the request (and tell the server you're sending it compressed); I honestly don't know if this is supported automatically, but it could certainly be done by the api explicitly checking for a particular header and applying gzip decompression on the payload
change the api to perform a number of small uploads, and a completion message
live with it
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;
}