Help with translating a PHP method to C# - 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.)

Related

Simple REST request c# - error

I am trying write simple request to REST service.Follow to documentation from REST Service provider:
I should use in header Content-Type: application/json.
Response return in json format
For authorization proccess I have to send two headers one with APIKey and second with APISign
Controller PING in REST service to test code.
I use .net 2.0
string sha1String = APIKey + "/rest/ping" + APISecret;
string XRestApiSign = SHA1HashStringForUTF8String(sha1String);
string data = "";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(restServer);
request.Method = "POST";
request.ContentType = "application/json";
request.Headers.Add("X-Rest-ApiSign", XRestApiSign);
request.Headers.Add("X-Rest-ApiKey", APIKey);
request.ContentLength = data.Length;
StreamWriter requestWriter;
Stream webStream = request.GetRequestStream();
using (requestWriter = new StreamWriter(webStream, System.Text.Encoding.ASCII)) ;
{
requestWriter.Write(data);
}
request.BeginGetResponse((x) =>
{
using (HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(x))
{
List<string> list = Newtonsoft.Json.JsonConvert.DeserializeObject<List<string>>(response.GetResponseStream().ToString());
}
}, null);
I should get response string PONG but I get below message
Unexpected character encountered while parsing value: S. Path '', line 0, position 0
Is code OK ? Why I get this message?
This is mostly the case because the script that generates the JSON on the server side adds the byte order mark to the response.
In your case, however, you're trying to convert the stream to JSON, not the content of the stream. You need to read all text from the stream and deserialize the object from that. You need to call one of the methods on the stream that reads the content.
I modified my code with yours suggestion and it works. Now I have problem with send data :)
Subscription user1 = new Subscription
{
Email = "kubaIt#test.com.pl",
List = "xfct2bjcdv",
};
List<Subscription> user = new List<Subscription>();
user.Add(user1);
string json = JsonConvert.SerializeObject(user);
string data = json;
I added above. Other code is the same. I got error :The request was aborted: The request was canceled."
json = [{\"email\":\"kubaIt#test.com.pl\",\"list\":\"xfct2bjcdv\"}] //value from debuger

cannot call web api successfully when sending xml data

I cannot successfully call an API using C# at the moment. I have attached a screen shot of the call being successfully made with Chrome PostMan although I'm not able to replicate it in C#. He is my attempt so far which fails. The response I get back from the server is included below. Can anyone see what I'm doing wrong?
Many thanks,
James
Code Snippet
const string xml = "<Envelope><Body> <AddRecipient>...";
var req = (HttpWebRequest)WebRequest.Create(ApiUrl);
var requestBytes = System.Text.Encoding.ASCII.GetBytes(xml);
req.Method = "POST";
req.Headers.Add("Authorization", "Bearer " + token);
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = requestBytes.Length;
var requestStream = req.GetRequestStream();
requestStream.Write(requestBytes, 0, requestBytes.Length);
requestStream.Close();
var res = (HttpWebResponse)req.GetResponse(); // Call API
var sr = new StreamReader(res.GetResponseStream(), System.Text.Encoding.Default);
var backstr = sr.ReadToEnd();
sr.Close();
res.Close();
Chrome PostMan
Response back from API
<Envelope><Body><RESULT><SUCCESS>false</SUCCESS></RESULT><Fault><Request/><FaultCode/><FaultString>Server Error</FaultString><detail><error><errorid>50</errorid><module/><class>SP.API</class><method/></error></detail></Fault></Body></Envelope>
Is there any documentation about what error 50 is? Could just be a bad pram? If not I recommend downloading fiddler. You can then properly compare the request from both PostMan and your application to see what the actual difference is.

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

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();

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>");

getting this error: "The remote server returned an error: (422) Unprocessable Entity." when doing post from C# to RoR

This code is for an outlook plugin. We're trying to POST to a page and are getting this error:
The remote server returned an error: (422) Unprocessable Entity.
The C# code is here:
webClient.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
ASCIIEncoding asciiEncoding = new System.Text.ASCIIEncoding();
Byte[] postData = asciiEncoding.GetBytes("email=e2#email.com&password=hunter2");
char[] resultHTML = asciiEncoding.GetChars(webClient.UploadData("http://url", "POST", postData));
string convertedResultHTML = new string(resultHTML);
Any idea what could be causing this?
POST data must be encoded prior to be sent out on the wire as ASCII, if you are sending character not in the ASCII range. You should try something like:
Byte[] postData = asciiEncoding.GetBytes(HttpUtility.UrlEncode("email=e2#email.com&password=hunter2"));
Because of its limited functionality, I avoid using WebClient and use WebRequest instead. The code below:
does not expect an HTTP 100 status code to be returned,
creates a CookieContainer to store any cookies we pick up,
sets the Content Length header, and
UrlEncodes each value in the post data.
Give the following a try and see if it works for you.
System.Net.ServicePointManager.Expect100Continue = false;
System.Net.CookieContainer cookies = new System.Net.CookieContainer();
// this first request just ensures we have a session cookie, if one exists
System.Net.WebRequest req = System.Net.WebRequest.Create("http://localhost/test.aspx");
((System.Net.HttpWebRequest)req).CookieContainer = cookies;
req.GetResponse().Close();
// this request submits the data to the server
req = System.Net.WebRequest.Create("http://localhost/test.aspx");
req.ContentType = "application/x-www-form-urlencoded";
req.Method = "POST";
((System.Net.HttpWebRequest)req).CookieContainer = cookies;
string parms = string.Format("email={0}&password={1}",
System.Web.HttpUtility.UrlEncode("e2#email.com"),
System.Web.HttpUtility.UrlEncode("hunter2"));
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(parms);
req.ContentLength = bytes.Length;
// perform the POST
using (System.IO.Stream os = req.GetRequestStream())
{
os.Write(bytes, 0, bytes.Length);
}
// read the response
string response;
using (System.Net.WebResponse resp = req.GetResponse())
{
if (resp == null) return;
using (System.IO.StreamReader sr = new System.IO.StreamReader(resp.GetResponseStream()))
{
response = sr.ReadToEnd().Trim();
}
}
// the variable response holds the results of the request...
Credits: Hanselman, Simon (SO Question)
This is the RoR application telling you that you have not formed a request that it can handle; the destination script exists (otherwise you'd see a 404), the request is being handled (otherwise you'd get a 400 error) and it's been encoded correctly (or you'd get a 415 error) but the actual instruction can't be carried out.
Looking at it, you seem to be loading some email information. The RoR application could be telling you that the username and password is wrong, or that the user doesn't exist, or something else. It's up to the RoR application itself.
I think the code itself is good; it's just that the app at the other end isn't happy about doing what you ask it. Are you missing something else in the request information, like a command? (eg command=getnetemails&email=e2#email.com&password=hunter2) Are you sure the email/password combination you are passing is good?
see here for more on the 422 error.
Add the below line above your code.
System.Net.ServicePointManager.Expect100Continue = false;
Are you trying to access an authentication required page?
it was solved by returning xml instead of just unstructured text on the RoR side

Categories