PHP/Curl-SSL operations alternative in C# - c#

I have this piece of code written in PHP, which adds, as i presume, some information about an SSL-certificate to a HTTP-request(It's just a simple http-request, isn't it?). It's added either to body-request or header, that i don't know for sure.
//some code before that
curl_setopt($curl,CURLOPT_SSLCERT,'cert.crt');
curl_setopt($curl,CURLOPT_SSLKEY,'cert.key');
//some code after
//the request itself
$json_response = curl_exec($curl);
The problem is - i don't know how to make this stuff in C#. It'd be easy if i had any knowledge how it's done in curl, like what it exactly does under it's cover.
My current request.
//
var request = CreateHttpRequest(url, method);
var json = param?.ToJson();
if (json != null)
{
var postData = Encoding.UTF8.GetBytes(json);
request.ContentLength = postData.Length;
using (var stream = request.GetRequestStream())
stream.Write(postData, 0, postData.Length);
}
using (var webResponse = request.GetResponse())
using (var streamReader = new StreamReader(webResponse.GetResponseStream(), Encoding.UTF8))
{
var result = streamReader.ReadToEnd();
return result.ParseJson(type);
}
//
private HttpWebRequest CreateHttpRequest(string url, HttpMethod method)
{
var request = (HttpWebRequest)WebRequest.Create(url);
request.ContentType = "application/json";
request.Accept = "application/json, application/javascript, text/*";
request.Headers.Add("Accept-Encoding", "gzip,deflate");
request.Method = method.ToString().ToUpper();
return request;
}

In order to use client certificate (loaded from .crt and .key files) in your HTTP-request, add following lines in CreateHttpRequest method before return:
string certificateText = File.ReadAllText("cert.crt");
string privateKeyText = File.ReadAllText("cert.key");
ICertificateProvider provider =
new CertificateFromFileProvider(certificateText, privateKeyText);
request.ClientCertificates.Add(provider.Certificate);
Taken from this answer. To have CertificateFromFileProvider install OpenSSL.X509Certificate2.Provider Nuget package.

Ended up using OpenSSL library.
public X509Certificate2 CreateCertifacte(string pathToCertificate)
{
var keyBytes = File.ReadAllBytes($"{pathToCertificate}/cert.key");
var certBytes = File.ReadAllBytes($"{pathToCertificate}/cert.crt");
var certBio = new BIO(certBytes);
var keyBio = new BIO(keyBytes);
var key = CryptoKey.FromPrivateKey(keyBio, "_");
var cert = new X509Certificate(certBio);
var name = cert.SerialNumber+".pfx";
var stacks = new Stack<X509Certificate>();
new X509Store().AddTrusted(cert);
var certRealPkcs12 = new PKCS12("_", key, cert, stacks);
using (var file = BIO.File(name, "wb"))
{
file.SetClose(BIO.CloseOption.Close); // don't ask me why, i don't know. this one just works.
certRealPkcs12.Write(file);
}
certRealPkcs12.Dispose();
var realCertOut =
new X509Certificate2(File.ReadAllBytes(name), "_");
return realCertOut;
}
Update:
For the netstandard version you can use my fork. Keep in mind that it hasn't been tested all the way through yet (not sure if i ever will), so something wont probably work.

Related

JSON format is being returned with missing data using C# (HTTPWEBREQUEST)

I'm working with JSON and C# ( HttpWebRequest ). Basically I have application to download a JSON from and API REST, but the problem is when I download it, the JSON comes missing some data, it seems that is cutting some data, with wrong structure. If I use a software which does the same thing that I'm developing, this problem doesn't happen. I'm sure that is something with my code, if I'm missing something. Here is my code:
var httpWebRequest = (HttpWebRequest)WebRequest.Create("MyURL");
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "GET";
string authInfo = "user" + ":" + "pass";
authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo));
httpWebRequest.Headers["Authorization"] = "Basic " + authInfo;
// Create the HttpContent for the form to be posted.
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var sr = new StreamReader(httpResponse.GetResponseStream(), Encoding.UTF8))
{
StreamWriter sw = new StreamWriter(#"C:\test\Stores.txt");
sw.Write(sr.ReadToEnd());
}
You can try this.its works in my code.
public static async Task MethodName()
{
using (HttpClientHandler handler = new HttpClientHandler() { UseCookies = false })
{
using (HttpClient httpClient = new HttpClient(handler))
{
httpClient.DefaultRequestHeaders.Authorization = Program.getAuthenticationHeader();
string filterQuery = Program.getURI().ToString();
using (HttpResponseMessage httpResponse = await httpClient.GetAsync(filterQuery).ConfigureAwait(false))
{
var streamContent = await httpResponse.Content.ReadAsStreamAsync();
FileStream fs = new FileStream("C:\test\Stores.Json", FileMode.Create);
streamContent.CopyTo(fs);
streamContent.Close();
fs.Close();
}
}
}
}
This can be an issue with your Http request (GET).
Step 1 - If you have a working software with the API, use Fiddler to analyse what is the http GET request it sends. You need to check the header info as well.
Step 2 - Compare the Http request with the HttpRequest you have created. There can be missing parameters etc.

convert curl php rest api calls to c# code

I've been trying to convert php code that accesses a json rest api into c# but cannot get this to work...
I cannot get a valid response back.. (400 Bad request)
Here is the curl im trying to convert:
curl --user bob#gmail.com:387653t253431a1b1d6687pl9836th5s \
--form url=http://bbc.com --form x-metrix-adblock=0 \
https://gtmetrix.com/api/0.1/test
Here is the code I've tried without success:
content = "http://bbc.com";
string result;
var req = HttpWebRequest.Create("https://gtmetrix.com/api/0.1/test");
req.Method = "POST";
var cc = new CredentialCache();
req.Credentials = new NetworkCredential(username, passkey);
req.ContentType = "application/json";
byte[] bytes = UTF8Encoding.UTF8.GetBytes(content);
req.ContentLength = bytes.Length;
using (var stream = req.GetRequestStream())
{
stream.Write(bytes, 0, bytes.Length);
}
using (var resp = req.GetResponse())
{
var results = new StreamReader(resp.GetResponseStream()).ReadToEnd();
result = JObject.Parse(results).ToString();
}
any help would be appreciated..
This is not a direct answer to your question, but I wanted to let you know that I’ve released an open source .Net client library which simplifies consuming the GTMetrix.net API. Submitting a test and retrieving the results is simple;
var client = Client(connection);
var request = new TestRequest(
new Uri("http://website.net"),
Locations.London,
Browsers.Chrome);
var response = client.SubmitTestAsync(request);
if (response.Result.StatusCode == HttpStatusCode.OK &&
response.Result.Body.State == ResultStates.Completed)
{
var pageLoadTime = response.Result.Body.Results.PageLoadTime;
...
}
The project (docs and code) can be found here GTmetrix-net on GitHub

Paypal HTTP post request gives Invalid Merchant or Merchant doesn't exist error in MVC C#

I am facing trouble in making an HTTP post request to Paypal for Secure token to use Paypal's Hosted solution but I am getting this error:
Some required information is missing or incorrect. Please correct the fields below and try again.
Error: Invalid Merchant or Merchant doesn't exist!
This is my C# code throught which I am making HTTP calls:
string strNVP = "https://pilot-payflowpro.paypal.com?PARTNER=PayPal&USER=myUsername&VENDOR=myVendorName&PWD=myPassword&TRXTYPE=A&AMT=" + obj.CurrentPackagePrice + "&CREATESECURETOKEN=Y&SECURETOKENID=" + Guid.NewGuid().ToString("N");
HttpWebRequest wrWebRequest = (HttpWebRequest)WebRequest.Create(strNVP);
wrWebRequest.Method = "POST";
StreamWriter requestWriter = new StreamWriter(wrWebRequest.GetRequestStream());
requestWriter.Write(strNVP);
requestWriter.Close();
HttpWebResponse hwrWebResponse = (HttpWebResponse)wrWebRequest.GetResponse();
StreamReader responseReader = new StreamReader(wrWebRequest.GetResponse().GetResponseStream());
//and read the response
string responseData = responseReader.ReadToEnd();
responseReader.Close();
string result = Server.UrlDecode(responseData);
string[] arrResult = result.Split('&');
Hashtable htResponse = new Hashtable();
string[] responseItemArray;
foreach (string responseItem in arrResult)
{
responseItemArray = responseItem.Split('=');
htResponse.Add(responseItemArray[0], responseItemArray[1]);
}
string responseResult = htResponse["RESULT"].ToString();
string response = htResponse["RESPMSG"].ToString();
///for Success response
if (responseResult == "0" && response == "Approved")
{
ViewBag.secureToken = htResponse["SECURETOKEN"].ToString();
ViewBag.secureTokenId = htResponse["SECURETOKENID"].ToString();
}
Kindly help me in this problem may b I have done some wrong in my code above also.
The issue was that I was unable to receive a Token and TokenID due to that this exception was arising and then I resolved my issue by making modifications in the above code so that the Paypal sends back a response with Token and TokenID which I used in iframe and its working perfect now.
var request = (HttpWebRequest)WebRequest.Create("https://pilot-payflowpro.paypal.com");
var postData = "PARTNER=PayPal&USER=myUser&VENDOR=myVendor&PWD=myPassword&TRXTYPE=A&AMT=50&CREATESECURETOKEN=Y&SECURETOKENID=" + Guid.NewGuid().ToString("N");
var data = Encoding.ASCII.GetBytes(postData);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = data.Length;
using (var stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
var responseData = (HttpWebResponse)request.GetResponse();
var responseString = new StreamReader(responseData.GetResponseStream()).ReadToEnd();
string result = Server.UrlDecode(responseString);
string[] arrResult = result.Split('&');
Hashtable htResponse = new Hashtable();
string[] responseItemArray;
foreach (string responseItem in arrResult)
{
responseItemArray = responseItem.Split('=');
htResponse.Add(responseItemArray[0], responseItemArray[1]);
}
string responseResult = htResponse["RESULT"].ToString();
string response = htResponse["RESPMSG"].ToString();
///for Success response
if (responseResult == "0" && response == "Approved")
{
ViewBag.secureToken = htResponse["SECURETOKEN"].ToString();
ViewBag.secureTokenId = htResponse["SECURETOKENID"].ToString();
}
The above code is buggy and throws exceptions while receiving a response etc. So this code block is working good.

Set a body for WebClient when making a Post Request

So I have an api that I want to call to. The first call is an ahoy call and in the body of the request I need to send the ship_type, piratename and my piratepass. I then want to read the response which has my treasure booty that i will use for later.
I'm able to do this with web request. but i feel like there is a better way to do it with webclient.
(way I currently do it in webrequest)
//Credentials for the Pirate api
string piratename = "IvanTheTerrible";
string piratepass= "YARRRRRRRR";
string URI = "https://www.PiratesSuperSecretHQ.com/sandyShores/api/respectmyauthority";
WebRequest wr = WebRequest.Create(URI);
wr.Method = "POST";
wr.ContentType = "application/x-www-form-urlencoded";
string bodyData = "ship_type=BattleCruiser&piratename=" + piratename + "&piratepass=" + piratepass;
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] byte1 = encoder.GetBytes(bodyData);
wr.ContentLength = byte1.Length;
//writes the body to the request
Stream newStream = wr.GetRequestStream();
newStream.Write(byte1, 0, byte1.Length);
newStream.Close();
WebResponse wrep = wr.GetResponse();
string result;
using (var reader = new StreamReader(wrep.GetResponseStream()))
{
result = reader.ReadToEnd(); // do something fun...
}
Thanks in advance either way.
You can do with this simple code
Uri uri = new Uri("yourUri");
string data = "yourData";
WebClient client = new WebClient();
var result = client.UploadString(uri, data);
Remember that you can use UploadStringTaskAsync if you want to be async
You can try like below as well:
public String wcPost(){
Map<String, String> bodyMap = new HashMap();
bodyMap.put("key1","value1");
WebClient client = WebClient.builder()
.baseUrl("domainURL")
.build();
String responseSpec = client.post()
.uri("URI")
.headers(h -> h.setBearerAuth("token if any"))
.body(BodyInserters.fromValue(bodyMap))
.exchange()
.flatMap(clientResponse -> {
if (clientResponse.statusCode().is5xxServerError()) {
clientResponse.body((clientHttpResponse, context) -> {
return clientHttpResponse.getBody();
});
return clientResponse.bodyToMono(String.class);
}
else
return clientResponse.bodyToMono(String.class);
})
.block();
return responseSpec;
}

C# WebRequest (Http POST over SSL) hangs at GetResponse() but different URL works. Also wrong POST parameters in a request

I found that this code works as expected:
var url = "https://limal.info/efulfilment.php";
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
var alternativeAnswer = Encoding.UTF8.GetString(new WebClient().UploadValues(url, new NameValueCollection() { { "xml", "test" } }));
The following code however gives me a headache:
var url = "https://limal.info/efulfilment.php";
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
var request = (HttpWebRequest)WebRequest.Create(url);
request.ContentType = "application/x-www-form-urlencoded";
request.Method = "POST";
request.Timeout = 5000; // I added this for you, so you only need to wait 5 sec...
using (var requestStream = request.GetRequestStream())
{
var writer = new StreamWriter(requestStream);
writer.Write("xml=test");
}
using (var response = request.GetResponse())
{
using (var responseStream = response.GetResponseStream())
{
var reader = new StreamReader(responseStream);
var answer = reader.ReadToEnd();
}
}
Somehow the post parameters don't get recognized and I get the response:
"limal.info bridge error: Missing 'xml' variable in post request."
(The correct answer would be that the XML data is wrongly formatted, as test is invalid XML...)
Now to the next Problem:
When I use a different url a timeout exception occurs. It hangs at UploadValues in the following code. (The other example that uses HttpWebRequest hangs at GetResponse, which I tried, too.)
var url = "https://sys.efulfilment.de/rt/";
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
var alternativeAnswer = Encoding.UTF8.GetString(new WebClient().UploadValues(url, new NameValueCollection() { { "xml", "test" } }));
I read about similar problems here and on other sites. It seems that using Http POST with SSL is a problem in .NET.
WHY?? :(

Categories