HTTPWebRequest Body Formatting - c#

This is a stupidly trivial question, but I can't seem to find a proper example anywhere with more than one property being set. Basically, I'm trying to send a POST request with C#'s HTTPWebRequest library while specifying two different fields in the body of the request.
So far, I have this:
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.Method = "POST";
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] byt = encoding.GetBytes("recipient=12345ABC");
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = byt.Length;
Stream newStream = request.GetRequestStream();
newStream.Write(byt, 0, byt.Length);
Followed by the usual GetResponse() stuff. This works fine, everything's dandy, but I can't figure out how to specify multiple body elements, such as both of these:
recipient=12345ABC
body="testmessage"
I've tried separating them with a semicolon, an ampersand, and a comma, but the server keeps returning Error 400: Bad Request. Perhaps I'm just misunderstanding how this process works?

API docs were sloppily done. Actual parameter names were "recipients" and "text" - code worked fine after this change.
URL encoding in the body works fine, "recipients=12345ABC&text=This+is+URL+escaped+text" worked like a charm in either the URL itself or the POST body.

Related

Http request ending as bad request due to Encoding and Escape character issues

Note: Code is in F# but tagging C# because it's a general encoding and escape character issue across .net while converting from object to json, please look at the output at the bottom of the page.
Following request is ending up a bad request, please have a look at any discrepancies especially in the Encoding.Default.GetString and then encoding back into System.Text.Encoding.ASCII.GetBytes especially.
Context: An object is serialized and written to the body of the PUT request and is ended up as bad request 400. JSON is serialized correctly and I can see the string with Console.WriteLine
I took the JSON encoding example from F# snippets
let update (schema: Article) : Article =
let url = "http://example.com"
use memoryStream = new MemoryStream()
(new DataContractJsonSerializer(typeof<Article>)).WriteObject(memoryStream, schema)
let d = Encoding.Default.GetString(memoryStream.ToArray()) // I suspect problem may be here
let data : byte[] = System.Text.Encoding.ASCII.GetBytes(d); // or here
let request = WebRequest.Create(url) :?> HttpWebRequest
request.Method <- "PUT"
request.ContentType <- "application/json;charset=UTF-8"
request.Accept <- "application/json;charset=UTF-8"
request.ContentLength <- (int64)data.Length
use requestStream = request.GetRequestStream()
requestStream.Write(data, 0, data.Length)
requestStream.Flush()
requestStream.Close()
let response = request.GetResponse() :?> HttpWebResponse
use reader = new StreamReader(response.GetResponseStream())
use memoryStream = new MemoryStream(ASCIIEncoding.Default.GetBytes(reader.ReadToEnd()))
let result = (new DataContractJsonSerializer(typeof<Article>)).ReadObject(memoryStream) :?> Article
reader.Close()
response.Close()
request.Abort()
result
Further Discoveries
I was able to get Charles Proxy up and I saw that forward slashes have been escaped in the output serialized json to the server.
Actual Output: with escaped slashes \ /
\/publication\/d40a4e4c-d6a3-45ae-98b3-924b31d8712a\/altasset\/c42d0df7-a563-4bb5-b7fa-313e6a98032f\/
Expected output: They are supposed to have forward slashes only, no escaping of the characters.
/publication/d40a4e4c-d6a3-45ae-98b3-924b31d8712a....
I guess something causing the character to be escaped in Encoding process, is there a way to fix it?
Edit
I also noticed that memoryStream.ToArray() returns a byte[] so instead of going through encodings I also tried the following but it didn't make any difference.
let data : byte[] = memoryStream.ToArray()
requestStream.Write(data, 0, data.Length)
in Charles proxy, I'm seeing Broken pipe message.
Add a reference to the Newtonsoft.Json NuGet package and add this to the top of your F# file:
open Newtonsoft.Json
Then try this as the body of your update method (it uses UTF-8 encoding explicitly rather than ASCII or the platform default):
let url = "http://example.com"
let serialized = JsonConvert.SerializeObject(schema)
let data : byte[] = Encoding.UTF8.GetBytes(serialized)
let request = WebRequest.Create(url) :?> HttpWebRequest
request.Method <- "PUT"
request.ContentType <- "application/json;charset=UTF-8"
request.Accept <- "application/json;charset=UTF-8"
request.ContentLength <- (int64)data.Length
use requestStream = request.GetRequestStream()
requestStream.Write(data, 0, data.Length)
requestStream.Flush()
requestStream.Close()
let response = request.GetResponse() :?> HttpWebResponse
use reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8)
let result = JsonConvert.DeserializeObject<Article>(reader.ReadToEnd())
reader.Close()
response.Close()
request.Abort()
result
Unless the server you're using was also using DataContractJsonSerializer (which escapes "/" as "\/") then you're probably better off with Newtonsoft. And it doesn't hurt to fix the UTF-8 encoding issues before they arise (it didn't look like you were sending/receiving any non-ASCII text but that would inevitably happen in the real world).

Changing HTTP Request to HTTPS, message content seems to be lost

This is not a subject I am strong in so I apologize ahead of time if I say something ridiculous.
I have developed an HTTP service using Mule. I have it functioning perfectly when I connect directly to the service and send data using a test harness I wrote in C#.
As the final part of my testing, I need to send it to an HTTPS URL that is supposed to "decrypt" the message and forward it to my service. When I send a message to the HTTPS URL, it gets forwarded to my service but the message contents appear empty and therefore does not get processed. I understand that I may have to add some "encryption" to my Test Harness but I have been researching how to do this all day and nothing I have found is answering my question.
Here is an example of the code I am using for the simple HTTP request:
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(ConfigurationManager.AppSettings["HttpDestination"].ToString());
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = data.Length;
using (Stream strm = req.GetRequestStream())
{
strm.Write(data, 0, data.Length);
}
HttpWebResponse response = (HttpWebResponse)req.GetResponse();
What do I need to change here to make this work?
Here is the solution that I discovered here. I needed to add the following line:
req.ProtocolVersion = System.Net.HttpVersion.Version10;
Without this, a timeout was occurring when getting the request stream and the content was never being sent, only the headers.

In C#, is it possible to open a URL in the background, without opening a browser?

My code needs to supply some information to a server via a php script.
Basically I want to call www.sitename.com/example.php?var1=1&var2=2&var3=3 but I don't want the browser to open, so Process.Start(URL); won't work.
Since I come to this site to learn and not to get answers, mostly, I will explain what I've done so far and the errors I have gotten. If you know a solution anyway, feel free to skip the next part.
I have looked around, and I saw a solution for using POST:
ASCIIEncoding encoding=new ASCIIEncoding();
string postData="var1=1&var2=2&var3=3";
byte[] data = encoding.GetBytes(postData);
// Prepare web request...
HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create("http://localhost/site.php");
myRequest.Method = "POST";
myRequest.ContentType="application/x-www-form-urlencoded";
myRequest.ContentLength = data.Length;
Stream newStream=myRequest.GetRequestStream();
// Send the data.
newStream.Write(data,0,data.Length);
newStream.Close();
However, I require the use of GET not POST. At first I thought the solution might be to change myRequest.Method = "POST"; to GET, but this didn't work because that's not how GET works, it pulls data from the URL.
So, then I attempted to change the previous code to:
HttpwebRequest myRequest= (HttpWebRequest)WebRequest.Create("http://localhost/site.php" + postData);
Stream newStream = myRequest.GetRequestStream();
newStream.Close()
Under the logic that it would call the URL, which would (hopefully) initiate the GET_ request on the php script, and then life would be dandy. This however resulted in the following error:
A first chance exception of type 'System.Net.ProtocolViolationException' occurred in System.dll
An unhandled exception of type 'System.Net.ProtocolViolationException' occurred in System.dll
Additional information: Cannot send a content-body with this verb-type.
Any help is appreciated, and thanks.
string postData="var1=1&var2=2&var3=3";
// Prepare web request...
HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(
"http://yourserver/site.php?" + postData);
myRequest.Method = "GET";
var resp =(HttpWebResponse) myRequest.GetResponse();
var result = new StreamReader(resp.GetResponseStream()).ReadToEnd();
Or maybe even simpler:
var data = new WebClient().DownloadString("http://yourserver/site.php?var1=1&var2=2&var3=3");
See the WebClient class for more options
You mostly seem to have gone down the right route:
string postData="var1=1&var2=2&var3=3";
// Prepare web request...
HttpwebRequest myRequest= (HttpWebRequest)WebRequest.Create(
"http://localhost/site.php?" + postData);
// Send the data.
myRequest.GetResponse();
Note that I've added the ? at the end of site.php.
We don't have to fiddle around with the request stream since that's all about putting things in the body of a request - and as you've stated, a GET request has its data in the URL, not in its body.
The easiest way is to use WebClient class. Using it it's just 2 lines of code, just supply your URL and use methods like DownloadString.

Communicating with an ASP website

I have a know a website that contains an open database of the result of an academic test.
http://nts.org.pk/NTSWeb/PPL_30Sep2012_Result/search.asp
I am expert with C# but newbie to web development.
Usually, using web browser, we can enter and roll number and server sends back the result. E.G. Use my Roll Num: 3912125
What I need to do is, use a C# application to communicate this roll null number and get anything, of my result. (any string is excepted, I will parse out my result from that string.)
How do I send query? when I don't know a list of possible query strings.
I tried this code:
string queryString = "RollNo=3912125";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(#"http://nts.org.pk/NTSWeb/PPL_30Sep2012_Result/search.asp");
request.UseDefaultCredentials = true;
request.ContentType = "application/x-www-form-urlencoded";
request.Method = "POST";
byte[] requestBytes = Encoding.UTF8.GetBytes(queryString);
request.ContentLength = requestBytes.Length;
using (var requestStream = request.GetRequestStream())
{
requestStream.Write(requestBytes, 0, requestBytes.Length);
requestStream.Close();
}
WebResponse response = request.GetResponse();
textBox1.AppendText(((HttpWebResponse)response).StatusDescription);
Stream dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
string responseFromServer = reader.ReadToEnd();
textBox1.AppendText(responseFromServer);
reader.Close();
dataStream.Close();
response.Close();
You have to append the querystring to the url like this:
string queryString = "RollNo=3912125";
string url = String.Format(#"http://foo/search.asp?{0}", queryString);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
You should take a look at the code in my answer to C# https login and download file. It gives a good demonstration of how to perform a POST request. As far as knowing what's valid to use for the query-formatted string in your POST, it's simply a matter of looking for appropriate input elements in the page content. It looks like what you have (RollNo) is correct. You may, however, need to also add the submit button value to your request as well depending on how the server behaves, giving you something like. RollNo=3912125&submit=submit.
You're most of the way there. Your queryString should look like RollNo=3912125&Submit=+Search+. When you are calling WebRequest.Create, the Url should in fact be http://nts.org.pk/NTSWeb/PPL_30Sep2012_Result/result.asp.
The rest of your code should work, though the answer #JamieSee recommended to you has some very good advice about wrapping things in using blocks correctly

Webservice and encoding

I connect to the web service as follows:
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(
"http://mywebserviceaddress.com/attributes=someatt");
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
using (StreamReader stIn = new StreamReader(
req.GetResponse().GetResponseStream(),Encoding.UTF8))
{
strResponse = stIn.ReadToEnd();
return strResponse;
}
However I get the response with (probably) bad encoding so as a result, on my page i get the following issue:
Am I doing something wrong or is it a third-party web service issue? How can I get the respone without this silly issues?
Here's the screenshot from debugger:
The page is probably not UTF8. It looks like special characters use the upper half of an ASCII character, so it's some kind of old charset. Reading it as UTF8 causes errors because the reader doesn't expect single-byte special characters.
Store the result of GetResponse() into a variable and output the contents of ContentTypeCharacterSet. If the server acts correctly, it shows the used charset in this property. Then, you can use the correct charset in your StreamReader.

Categories