ProtocolViolationException while sending POST request - c#

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.

Related

c# How to send HTTP command as this - http://192.168.10.1/api/control?alert=101002

I have this hardware from Patlite,
This hardware has an HTTP command control function, for example, if I copy the url "http://192.168.10.1/api/control?alert=101002" to chrome in my computer, it will activate the hardware as needed.
I want to send the command from my code.
I tried this code with no luck:
System.Net.ServicePointManager.Expect100Continue = false;
WebRequest request = WebRequest.Create("http://10.0.22.222/api/control");
request.Method = "post";
request.ContentType = "application/x-www-form-urlencoded";
string postData = "alert=101002";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
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();
WebResponse response = request.GetResponse();
There is a picture from the manual:
Thanks
You need to create a webrequest instance for this.
WebRequest request = WebRequest.Create("http://192.168.10.1/api/control?alert=101002");
WebResponse response = request.GetResponse();
You may need to set some properties as request method and credentials for this to work.
See this:
https://msdn.microsoft.com/en-us/library/456dfw4f(v=vs.100).aspx
public static string Get(string url, Encoding encoding)
{
try
{
var wc = new WebClient { Encoding = encoding };
var readStream = wc.OpenRead(url);
using (var sr = new StreamReader(readStream, encoding))
{
var result = sr.ReadToEnd();
return result;
}
}
catch (Exception e)
{
//throw e;
return e.Message;
}
}
like this code use the url "http://192.168.10.1/api/control?alert=101002" to send get request.Good luck!

Remote Server returns error 401 Unauthorized Webexception (POST)

I'm trying to solve an issue that I Mostly (70%) have (30% is succesfull).
I trying to do a webrequest (POST) with the following code:
private string HttpWebRequest(string busStopCode)
{
//XML input
string xml = "<?xml version='1.0' encoding='UTF-8' standalone='yes'?><Siri version='1.0' xmlns='http://www.siri.org.uk/'><ServiceRequest> <RequestTimestamp>2011-10-24T15:09:12Z</RequestTimestamp><RequestorRef><username></RequestorRef><StopMonitoringRequest version='1.0'> <RequestTimestamp>2011-10-24T15:09:12Z</RequestTimestamp><MessageIdentifier>12345</MessageIdentifier><MonitoringRef>"+busStopCode+"</MonitoringRef></StopMonitoringRequest></ServiceRequest></Siri>";
string responseFromServer = null;
// Create a request using a URL that can receive a post.
WebRequest request = WebRequest.Create("http://<username>:<username>#nextbus.mxdata.co.uk/nextbuses/1.0/1");
// Set the Method property of the request to POST.
request.Method = "POST";
request.Credentials = CredentialCache.DefaultNetworkCredentials;
// Create POST data and convert it to a byte array.
string postData = xml;
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 = null;
while (response == null)
{
try
{
response = request.GetResponse();
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}
// Display the status.
MessageBox.Show(((HttpWebResponse)response).StatusDescription + " Completed");
// 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.
responseFromServer = reader.ReadToEnd();
// Clean up the streams.
reader.Close();
dataStream.Close();
response.Close();
return responseFromServer;
}
When I call this function I get mostly a messagebox of my exception with:
"System.Net.WebException: The remote Server returned an error(401) not authorized with System.Net.Http.Webrequest.GetResponse() with WindowsFormApplication1.Form1.HttpWebRequest(string BusstopCode) in <my pathfile>...."
What I'm doing wrong?
I already tried several solutions from previous threads but without success...
Thanks!

How do I copy a HttpRequest to another web service?

I have two identical web services currently installed on the same PC for testing purposes. A request that is received by the first service, is suposed go to the second one as well. My intention was to do this using a HttpModule. I handle the request during application.BeginRequest.
public void AsyncForwardRequest(HttpRequest request)
{
try
{
// Prepare web request...
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(WSaddress);
req.Credentials = CredentialCache.DefaultCredentials;
req.Headers.Add("SOAPAction", request.Headers["SOAPAction"]);
req.ContentType = request.Headers["Content-Type"];
req.Accept = request.Headers["Accept"];
req.Method = request.HttpMethod;
// Send the data.
long posStream = request.InputStream.Position;
long len = request.InputStream.Length;
byte[] buff = new byte[len];
request.InputStream.Seek(0, SeekOrigin.Begin);
if (len < int.MaxValue && request.InputStream.Read(buff, 0, (int)len) > 0)
{
using (Stream stm = req.GetRequestStream())
{
stm.Write(buff, 0, (int)len);
}
request.InputStream.Position = posStream;
DebugOutputStream(request.InputStream);
request.InputStream.Seek(0, SeekOrigin.Begin);
IAsyncResult result = (IAsyncResult)req.BeginGetResponse(new AsyncCallback(RespCallback), req);
}
}
catch (Exception ex)
{
App.Error2(String.Format("RequestDuplicatorModule - BeginRequest; ERROR begin request: {0}", ex.Message), ex);
}
private static void RespCallback(IAsyncResult asynchronousResult)
{
try
{
// State of request is asynchronous.
var req = (HttpWebRequest)asynchronousResult.AsyncState;
WebResponse resp = (HttpWebResponse)req.EndGetResponse(asynchronousResult);
Stream responseStream = resp.GetResponseStream();
System.IO.Stream stream = responseStream;
Byte[] arr = new Byte[1024 * 100];
stream.Read(arr, 0, 1024 * 100);
if (arr.Length > 0)
{
string body = (new ASCIIEncoding()).GetString(arr);
Debug.Print(body);
}
}
catch (WebException ex)
{
App.Error2(String.Format("RequestDuplicatorModule - BeginRequest; ERROR begin request: {0}", ex.Message), ex);
}
}
This (HttpWebResponse)req.EndGetResponse(asynchronousResult) throws an exception: 500 Internal Server Error and fails. The original request goes through fine.
request.InnerStream:
...
Does this have anything to do with the web service addresses being different? In my case they're:
http://localhost/WS/service.asmx
http://localhost/WS_replicate/service.asmx
I would at least implement this, to be able to read the content of a httpwebrequest that has a status 500:
catch (WebException ex)
{
HttpWebResponse webResponse = (HttpWebResponse)ex.Response;
Stream dataStream = webResponse.GetResponseStream();
if (dataStream != null)
{
StreamReader reader = new StreamReader(dataStream);
response = reader.ReadToEnd();
}
}
Not answering your question though, i would suggest having a simple amsx that reads the request, and posts the request to the two different web services. If you need some code for that let me know.
Additional advantages would be that the asmx will be easier to support for the developer as well as the one dealing with the deployment. You could add configuration options to make the actual url's dynamic.
Was able to modify the AsyncForwardRequest method so that I can actually edit the SoapEnvelope itself:
string buffString = System.Text.UTF8Encoding.UTF8.GetString(buff);
using (Stream stm = req.GetRequestStream())
{
bool stmIsReadable = stm.CanRead; //false, stream is not readable, how to get
//around this?
//solution: read Byte Array into a String,
//modify <wsa:to>, write String back into a
//Buffer, write Buffer to Stream
buffString = buffString.Replace("http://localhost/WS/Service.asmx", WSaddress);
//write modded string to buff
buff = System.Text.UTF8Encoding.UTF8.GetBytes(buffString);
stm.Write(buff, 0, (int)buff.Length);
}

C#: How to POST large string via WebRequest?

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

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