What is the equivalent way to set post parameters in .net? - c#

I have to integrate with a third party API. To use the service, I have to "POST" to a specific url with certain parameters.
The example code provided by the service is in php and is as follows
$data = array('From' => '0999999', 'To' => '08888888');
$curl = curl_init();
curl_setopt($curl, CURLOPT_FAILONERROR, true);
curl_setopt($curl, CURLOPT_RETURNTRANSFER,true);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); <--- Ignore SSL warnings
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
I am trying to use the WebRequest class to achieve the same in .net. However, I am a bit confused about how to set the post parameter data. I figured $data above is nothing but a Dictionary. So I created a equivalent dictionary. However, how do I set the post parameters with the dictionary values?
In http://msdn.microsoft.com/en-us/library/debx8sh9.aspx, they have serialized a string to a byte array and then set is as the post parameter in the dataStream. How do I do the same for a Dictionary?
Or is my approach incorrect? Is there a better way to do this?

Generally, WebClient.UploadValues is going to be the easiest approach here; see MSDN for a full example. Note, however, that this only covers CURLOPT_POSTFIELDS and CURLOPT_POST. Fail on error is automatic and implicit, and the response is already included as a byte[].
i.e.
using(var client = new WebClient()) {
var data = new NameValueCollection();
data.Add("From", "0999999");
data.Add("To", "08888888");
var result = client.UploadValues(url, data);
}
note POST is implicit here; if you need a different http method, use the overload:
var result = client.UploadValues(url, "PUT", data); // for example

If you are using url encoded post data you can url encode each key/value pair of your dictionary using HttpServerUtility.UrlEncode Method (String)
// Build postData
StringBuilder post = new StringBuilder();
foreach(item in dictionary) {
post.AppendFormat("&{0}={1}", item.key, HttpUtility.UrlEncode(item.value));
}
string postData = post.ToString();
// HTTP POST
Uri uri = new Uri(url);
request = (HttpWebRequest) WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = postData.Length;
using(Stream writeStream = request.GetRequestStream())
{
UTF8Encoding encoding = new UTF8Encoding();
byte[] bytes = encoding.GetBytes(postData);
writeStream.Write(bytes, 0, bytes.Length);
}

Just in case you have to use HttpWebRequest, the code below converts a Dictionary<String,String> named formVars to a byte[] named toPost:
byte[] toPost = System.Text.Encoding.UTF8.GetBytes(
String.Join("&", formVars.Select(x =>
HttpUtility.UrlEncode(x.Key) + "=" +
HttpUtility.UrlEncode(x.Value)));
);
Play with a working copy at https://dotnetfiddle.net/IOzIE6

You probably want to use the
http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.aspx
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("http://url");
request.AllowWriteStreamBuffering = true;
request.Method = "POST";
string post = "From=0999999&To=08888888";
request.ContentLength = post.Length;
request.ContentType = "application/x-www-form-urlencoded";
StreamWriter writer = new StreamWriter(request.GetRequestStream());
writer.Write(post);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();

Related

PayPal Pay Operation - error 81002

I'm not sure why this PayPal Pay operation is giving me this error even though I seem to have covered all the required fields:
Error Code: 81002 Severity: Error Message: Unspecified Method (Method Specified is not Supported)"
string postData = JsonConvert.SerializeObject(request);
value of postData:
"actionType=PAY
&currencyCode=USD
&cancelUrl=https%3a%2f%2fexample.com%2fcancel
&returnUrl=https%3a%2f%2fexample.com%2freturn
&requestenvelope.errorLanguage=en_US
&receiverList.receiver(0).email=recipientemail%40gmail.com
&receiverList.receiver(0).amount=0.05
&VERSION=94.0
&USER=bizemail-facilitator_api1.gmail.com
&PWD=xxxxx
&SIGNATURE=xxxxxxxxx"
Here's how I do the post:
SendRequest("https://api-3t.sandbox.paypal.com/nvp", postData);
public string SendRequest(string url, string postData)
{
var uri = new Uri(url);
var request = WebRequest.Create(uri);
var encoding = new UTF8Encoding();
var requestData = encoding.GetBytes(postData);
request.ContentType = "application/x-www-form-urlencoded";
request.Method = "POST";
request.Timeout = (300*1000); //TODO: Move timeout to config
request.ContentLength = requestData.Length;
using (var stream = request.GetRequestStream()) {
stream.Write(requestData, 0, requestData.Length);
}
var response = request.GetResponse();
string result;
using (var reader = new StreamReader(response.GetResponseStream(), Encoding.ASCII)) {
result = reader.ReadToEnd();
}
return result;
}
The method PAY doesn't exist on the NVP api. Full list of methods supported by that API is found here.
The PAY method, however, is defined in the Adaptive Payments API. Depending on your needs, you have two options:
Change the endpoint to https://svcs.paypal.com/AdaptivePayments/PAY and modify your values
Use another method, like DoDirectPayment, but I'm not sure it does what you want to.
I assume the value of postData is before you serialize it to a JSON string, instead of after as you say, since it is clearly not a JSON string.
If so, then it is already x-www-form-urlencoded, and you do not need to serialize it to a JSON string at all.
Or if you do after all, then change just this: request.ContentType = "application/json";

WebRequest POST form containing XML?

I am trying to use .Net WebRequest to POST a form. The form contains fields that are XML. (Among other things) I have tried the following code:
WebRequest req = WebRequest.Create(ctx.SvcUrl);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
using (var writer = new StreamWriter(req.GetRequestStream(), System.Text.Encoding.ASCII))
{
string reqBody = "first=<bill/>&last=smith"; //(embedded <>) - 500 Internal Server Error
writer.Write(reqBody);
}
rsp = req.GetResponse();
var strm = rsp.GetResponseStream();
var rdr = new StreamReader(strm);
string input = rdr.ReadToEnd();
The <> in reqBody causes a 500 - Internal Server error.
What's the right way to encode this? Or are multi-part forms the answer??
Try using:
string reqBody = string.Format("first={0}&last={1}", HttpUtility.HtmlEncode("<bill/>"), "smith");
You need to encode the request. Use the HttpEncoder class.
using System.Web.Util;
WebRequest req = WebRequest.Create(ctx.SvcUrl);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
using (var writer = new StreamWriter(req.GetRequestStream(),
System.Text.Encoding.ASCII))
{
var encoder = new HttpEncoder();
string reqBody = String.Format("first={0}&last={1}",
encoder.HtmlEncode("<bill/>"),
encoder.HtmlEncode("smith") );
writer.Write(reqBody);
}
rsp = req.GetResponse();
var strm = rsp.GetResponseStream();
var rdr = new StreamReader(strm);
string input = rdr.ReadToEnd();
I used String.Format() because I thought it looked nicer and made it clearer what I was doing, but it isn't necessary. You can build the string through string concatenation, too, as long as you pass it through HttpEncoder.HtmlEncode() first.
It turns out that UrlEncoding is being done automatically, so doing it myself can cause trouble. Also, the server I was connecting to couldn't handle any encoding. This muddied the water and made it difficult to see what was failing.
Bottom line solution was to get the server fixed to handle UrlEncoding.
As 'cheong00 on Microsoft's Forums' points out, to avoid the automatic, use TcpClient. But the encoding should be there.

StreamSend API Blast, Sending Email

I need to use StreamSend API to send email, here is
StreamSend API Reference
I am making web request as post to following URL with proper credentials
https://app.streamsend.com/audiences/2/blasts.xml
StringBuilder sb = new StringBuilder();
sb.Append("https://app.streamsend.com/audiences/2/blasts.xml");
Uri uri = new Uri(sb.ToString());
HttpWebRequest request = WebRequest.Create(uri) as HttpWebRequest;
request.ContentType = "application/xml";
StringBuilder strMail= new StringBuilder();
strMail.Append("<blast> ALL from api..... </blast>");
byte[] data = Encoding.ASCII.GetBytes(strMail.ToString());
Stream input = request.GetRequestStream();
input.Write(data, 0, data.Length);
input.Close();
HttpWebResponse nsResponse = (HttpWebResponse)request.GetResponse();
i am having err# 422 or 500. i would appreciate any help.
A couple of things. First, it looks like you're trying to do a POST request (you're sending data in the request stream). If you really want a POST request, you have to set request.Method = "POST";
Also, if you want an XML response, you need to set the Accept header. According to the documentation you listed, you need: request.Accept = "application/xml";
And you need to add your login id to the request, as well. I'm not sure how that's done. Perhaps in the request.Credentials property like this:
request.Credentials = new NetworkCredential("login_id", "your_key_here");
Finally, there's no reason to use StringBuilder if all you're doing is assigning strings. You can write, for example:
string urlString = "https://app.streamsend.com/audiences/2/blasts.xml"
Uri uri = new Uri(urlString);
or
byte[] data = Encoding.ASCII.GetBytes("<blast> ALL from api..... </blast>");

Help with translating a PHP method to C#

Can anyone help? I have a PHP method that sends an http post:
<?php
// API URL
$api_url = "url_of_the_API ";
// Apache auth
$api_user = "user";
$api_pass = "pass";
// Request
$xml = "";
$context = stream_context_create(
array (
'http' => array(
'method' => 'POST',
'header' => sprintf("Authorization: Basic %s\r\n",
base64_encode($api_user.':'.$api_pass))
."Content-type: application/x-www-form-urlencoded\r\n",
'content' => http_build_query(array('xml' => $xml)),
'timeout' => 5,
),
)
);
$response = file_get_contents($api_url,false,$context);
header ("Content-Type:text/xml");
echo $response;
?>
I need to translate this to C# and I am getting a reply back from the webservice saying "POST call with XML required". I am being told that:
"the XML is not being sent via POST in the 'xml' (name) variable? This is a similar process to submitting a webform with one variable called 'xml'."
Below is my C#
// this is where we will send it
const string uri = "theUri";
// create a request
var request = (HttpWebRequest)
WebRequest.Create(uri); request.KeepAlive = false;
request.ProtocolVersion = HttpVersion.Version10;
request.Method = "POST";
request.Credentials = new NetworkCredential("theUserName", "thePassword");
// turn our request string into a byte stream
var postBytes = Encoding.ASCII.GetBytes(postData);
// this is important - make sure you specify type this way
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = postBytes.Length;
var requestStream = request.GetRequestStream();
// now send it
requestStream.Write(postBytes, 0, postBytes.Length);
requestStream.Close();
// grab te response and print it out to the console along with the status code
var response = (HttpWebResponse)request.GetResponse();
Console.WriteLine(new StreamReader(response.GetResponseStream()).ReadToEnd());
Console.WriteLine(response.StatusCode);
Just as the error message says, you need to prepend xml= to your postData (just before converting it to bytes). In other words, your C# code skips this step:
$postdata = http_build_query(array('xml' => $xml))
and does this instead:
$postdata = $xml;
(In such cases, it has always helped me to set up Wireshark/tshark/tcpdump on either of the connection endpoints (in this case, probably on your server) and then compare the HTTP requests made by the two scripts. It's easy to notice the differences that way.)

How to retrieve an html redirected webpage programmatically?

I have done this code to login,to retrieve and show a webpage :
// login info array
string postData = "user_name=tler";
postData += "&user_password=lodvader";
byte[] data = Encoding.ASCII.GetBytes(postData);
// web request
WebRequest req = WebRequest.Create("http://www.lol.com/login.php");
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = data.Length;
// stream response to string
Stream newStream = req.GetRequestStream();
newStream.Write(data, 0, data.Length);
newStream.Close();
StreamReader reader = new StreamReader(req.GetResponse().GetResponseStream(), Encoding.GetEncoding("iso-8859-1"));
string responseString = reader.ReadToEnd();
// retrieve text within title
Regex rx = new Regex(#"(?<=<title>).+?(?=</title>)");
var variable = rx.Matches(responseString);
// output
Console.WriteLine(variable[0]);
Console.ReadLine();
But, the following page after login is an html redirect like :
<meta http-equiv="refresh" content="3; URL="bb.php">
How to follow this link and retrieve next page ?
Just send a new WebRequest to the bb.php file. Make sure that you use the same CookieContainer since I presume that login.php uses cookie-based sessions to remember you. Check out the HttpWebRequest.CookieContainer property. This requires you to cast your WebRequest to a HttpWebRequest.
Added: (Couldn't write example code in the comment.)
I'm just making code up without proofing now...
var cookies = new CookieContainer();
var firstReq = (HttpWebRequest)WebRequest.Create(".../login.php");
firstReq.CookieContainer = cookies;
var secondReq = (HttpWebRequest)WebRequest.Create(".../bb.php");
secondReq.CookieContainer = cookies
I have found the time to finish it, here the response ( i tried to be as clear as possible ) :
// Cookie for our session
var cookieContainer = new CookieContainer();
// Encode post variables
ASCIIEncoding encoding=new ASCIIEncoding();
byte[] loginDataBytes = encoding.GetBytes("user_name=belaz&user_password=123");
// Prepare our login HttpWebRequest
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://blabla.fr/verify.php");
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.CookieContainer = cookieContainer;
request.ContentLength = loginDataBytes.Length;
// Write encoded post variable to the stream
Stream newStream = request.GetRequestStream();
newStream.Write(loginDataBytes, 0, loginDataBytes.Length);
newStream.Close();
// Retrieve HttpWebResponse
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
// Link the response cookie to the domain
cookieContainer.Add(new Uri("http://blabla.fr/"),response.Cookies);
// Prepare our navigate HttpWebRequest, and set his cookie.
HttpWebRequest requestProfile = (HttpWebRequest)WebRequest.Create("http://blabla.fr/bb.php");
requestProfile.CookieContainer = cookieContainer;
// Retrieve HttpWebResponse
HttpWebResponse responseProfile = (HttpWebResponse)requestProfile.GetResponse();
// Retrieve stream response and read it to end
Stream st = responseProfile.GetResponseStream();
StreamReader sr = new StreamReader(st);
string buffer = sr.ReadToEnd();
There is a property of HttpWebRequest called AllowAutoRedirects. Set this to true. Also there is a property called MaximumAutomaticRedirections. Set that to some allowable value to make sure all of them are followed.
You can't do it a easy way, since the meta tag is read by the client and executed.
In this case, when you're using HttpWebRequest, the request doesn't care about the functions the text may have.
So you need to do another request to the page in the URL attribute (bb.php).
-
If the server did the redirection you wouldn't have the problem.

Categories