Https POST from Php to C#
Asked Answered
H

3

0

I have to make a post to a third party https url to get data procesed and sent back. And all I have as an example is this:

$signature= foo_string;
$data_to_post = json_dictionary;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $base_url);
curl_setopt($ch, CURLOPT_USERPWD, "$user:$password");
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER,array('Content-Type: application/json'));
curl_setopt($ch, CURLOPT_HTTPHEADER,array("JSON-Signature: $signature"));
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_to_post);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$data = curl_exec($ch);
curl_close($ch);

As we work with ASP .NET C# 2.0, I have to port this, but I get always a not autenticated error.

Here is what I'm doing:

HttpWebRequest q = (HttpWebRequest)WebRequest.Create(Host + ":" + Port);
                ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(new interhanse().AcceptAllCertifications);                

                q.Method = "POST";
                q.Headers.Add("JSON-Signature:" + GetSignature(data));
                q.ContentType = "application/json";

                q.UseDefaultCredentials = false;
                q.Credentials = new NetworkCredential(user,pwd, Host);

                byte[] buffer = UTF8Encoding.UTF8.GetBytes(data);

                q.ContentLength = data.Length;                

                Stream oStream = q.GetRequestStream();
                StreamWriter oWriter = new StreamWriter(oStream);
                oWriter.Write(buffer);
                oWriter.Close();


                HttpWebResponse reps = q.GetResponse() as HttpWebResponse;

I've read all SO questions I can find about this, but I don't get any improvements. Thanks in advance!

Hinge answered 17/9, 2009 at 15:44 Comment(0)
N
2

Well, one thing you're doing wrong is assuming that the length in bytes is the same as the length in characters. You should use buffer.Length for the content length. You're also calling StreamWriter.Write with a byte array. You shouldn't do that - you should just use the stream, as you've already done the encoding:

byte[] buffer = Encoding.UTF8.GetBytes(data);

q.ContentLength = buffer.Length;
using (Stream stream = q.GetRequestStream())
{
    stream.Write(buffer, 0, buffer.Length);
}

Now, that won't solve the authentication issue. You may find that just setting PreAuthenticate solves that though:

q.PreAuthenticate = true;

If that doesn't work, I suggest you run WireShark and look at the differences between the request through Curl and the request from .NET.

Notwithstanding answered 17/9, 2009 at 15:51 Comment(1)
Thanks, error changed now to: "Connection Terminated. Unexpeted reception error." But as they are custom errors, I'll ask support now :D Thanks a lot!Hinge
D
1

I think you should not supply the host in the authentication...

q.Credentials = new NetworkCredential(user,pwd);

Which would be something like:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Host + ":" + Port);
ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(new interhanse().AcceptAllCertifications);

request.Method = "POST";
request.Headers.Add("JSON-Signature:" + GetSignature(data));
request.ContentType = "application/json";

request.UseDefaultCredentials = false;
request.Credentials = new NetworkCredential(user, pwd);

byte[] buffer = UTF8Encoding.UTF8.GetBytes(data);

request.ContentLength = buffer.Length;
using (Stream oStream = request.GetRequestStream()) {
    oStream.Write(buffer, 0, buffer.Length);
}
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) {
    // load data from response here
}

Also you should avoid assigning the service point validation delegate on each request, this may slow down the requests increasingly because the validation is performed multiple times, and it's also kind of a memory leak.

Duodenary answered 17/9, 2009 at 15:54 Comment(1)
Didn't change the error, but as it isn't in the example I won't pass it anymore.Hinge
L
1
curl_setopt($ch, CURLOPT_USERPWD, "$user:$password");

Here is how you add that CURLOPT_USERPWD in Asp.Net:

    private async Task<string> Execute(string url, string query, string user, string pasword)
    {
        HttpClient httpClient = new HttpClient();
        var baseUri = new Uri(url, UriKind.Absolute);  // e.g. http://somedomain.com/endpoint
        Uri request = new Uri(baseUri, query);    // with query e.g. http://somedomain.com/endpoint?arg1=xyz&arg2=abc

        // Add a new Request Message
        HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, request);

        // add headers -> CURLOPT_USERPWD equivalent
        var encodedStr = Convert.ToBase64String(Encoding.Default.GetBytes(string.Format("{0}:{1}", user, password)));
        var authorizationKey = "Basic" + " " + encodedStr;    // Note: Basic case sensitive
        requestMessage.Headers.Add("Authorization", authorizationKey);

        // if POST - do this instead
        // content
        //HttpContent content = new StringContent(jsonContent);     // string jsonContent i.e. JsonConvert.SerializeObject(YourObject);
        //requestMessage.Content = content;
        //requestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");

        // execute
        HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
        var responseString = await responseMessage.Content.ReadAsStringAsync();    // reads it as string; 

        // if json and you need to convert to an object do this
        // var myresponse = JsonConvert.DeserializeObject<YourMappedObject>(responseString);

        return responseString;
    }
Lapointe answered 5/2, 2015 at 13:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.