How do you send a certificate with an HttpRequestMessage? - c#

Here I have an HttpRequestMessage, and I am trying to add a client certificate to it, but cannot seem to find how to do this. Has anyone out there done something like this?
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "myapi/?myParm=" + aParm);
//Want to add a certificate to request - a .p12 file in my project
myAPIResponse res = await SendAndReadAsAsync<myAPIResponse>(request, aCancelToken);

Here is an answer combining HttpClient with HttpRequestMessage.
The HttpRequestMessage holding the data and client handling how the data is sent.
WebRequestHandler handler = new WebRequestHandler();
X509Certificate certificate = GetMyX509Certificate();
handler.ClientCertificates.Add(certificate);
HttpClient client = new HttpClient(handler);
var request = new HttpRequestMessage (HttpMethod.Get, "myapi/?myParm=" + aParm);
HttpResponseMessage response = await client.SendAsync (request);
response.EnsureSuccessStatusCode();
Edit: Here is a link explaining the difference between WebRequestHandler, HttpClientHandler & HttpClient to understand which one you should use when: https://learn.microsoft.com/en-us/archive/blogs/henrikn/httpclient-httpclienthandler-and-webrequesthandler-explained

Related

C# API Beginner

I have the following code as a start to create a API Call to https://jsonplaceholder.typicode.com/posts/. I want to practice making the call, receive a JSON response and then..do stuff.
How can I finish this off to get a response so I can iterate through the response array.
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(URL);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get,"");
request.Content = new StringContent(URL, Encoding.UTF8,"application/json");
Wiring this in VS Code so will need to install packages if needed.
Thank you!
You are almost there. Try (if you want a simple synchronous send):
HttpClient client = new HttpClient();
string responseString;
using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, new Uri("<insert your URL>"))) {
HttpResponseMessage response = client.SendAsync(request).Result;
// Get the response content as a string
responseString = response.Content.ReadAsStringAsync().Result;
}
Note that it's good practice to initialize one instance of HttpClient and reuse it to send multiple requests (rather than initialize one every time you need to send something).
Any headers, URLs and such specific to a message should be set in the HttpRequestMessage class (which should be disposed of with the "using ..." term.

Is it possible to generate headers automatically with HttpClient / RestSharp?

At the moment I am using the following RestSharp request to get a website's content:
var client = new RestClient(productLink);
var request = new RestRequest(Method.GET);
request.AddHeader("Cookie", "insert-cookie-content");
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
I have tried converting it into HttpClient as i will need to use the AllowRedirect property later:
var client = new HttpClient();
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Add("Cookie", "insert-cookie-content");
var response = await client.GetAsync(productUrl);
Console.WriteLine(response);
The URL I am trying to get a response from is: https://www.nike.com/sg/launch/t/air-max-90-orange-duck-camo
My first problem is that the HttpClient request is giving me 403 Errors whereas the RestClient request was working fine. How can I fix this?
My second problem is that the cookie expires after a couple of uses, and I have to manually get a new one from postman and insert it. Is there anyway for the request to generate its own cookie?
Here is the two fiddler responses compared: https://imgur.com/a/bZo7d9F
In case of HttpClient if you want to pass the Cookies manually through the DefaultRequestHeaders then you have to tell this to the HttpClient to do NOT use CookieContainer. You have to use HttpClientHandler's UseCookie flag to indicate it.
var client = new HttpClient(new HttpClientHandler { UseCookies = false });
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Add("Cookie", "insert-cookie-content");
var response = await client.GetAsync(productUrl);
Console.WriteLine(response);

Bypass certificate using .Net HttpClient

I'm trying to post a REST message to a website that has a certificate problem. Until our IT guy can resolve it, I need to bypass this when executing the
PostAsync call.
For some reason the ServerCertificateCustomValidationCallback is no longer part of the HttpClientHandler. Is there a another approach to resolve
this to avoid the permissions error? Thanks.
Here's a sample of what I'm doing.
string json = JsonConvert.SerializeObject(new
{
Message = new
{
TestID = "1",
}
});
var spHandler = new HttpClientHandler()
{
ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) =>
{
return true;
}
};
System.Net.Http.HttpClient client = new System.Net.Http.HttpClient(spHandler,true);
client.BaseAddress = new System.Uri("https://test.com");
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
var content = new StringContent(json, Encoding.UTF8, "application/json");
HttpResponseMessage msg = client.PostAsync(#"/Test", content).Result;
Edited: (Fix '/' delimiter issue)
From
client.BaseAddress = new System.Uri("https://test.com");
HttpResponseMessage msg = client.PostAsync(#"/Test", content).Result;
To
client.BaseAddress = new System.Uri("https://test.com/");
HttpResponseMessage msg = client.PostAsync("Test", content).Result;
I actually found the problem and edited the question above. Turns out you cant use a leading '/' on the uri PostAsync query. This was causing the problem. The handler was actually fine.
I was successfully bypassed certificate validation by the following steps:
Get the certificate
X509Certificate2 clientCert = GetClientCertificate();
Create request handler and pass the certificate
WebRequestHandler requestHandler = new WebRequestHandler();
requestHandler.ClientCertificates.Add(clientCert);
Call the handler
System.Net.ServicePointManager.ServerCertificateValidationCallback +=
delegate { return true; };
Create HttpClient object passing the handler and call the service.
HttpClient client = new HttpClient(requestHandler)
I hope this is useful for you.

Adding authentication header to HttpClient

I'm trying to access an API, but all the documentation is in PHP and I'm not very familiar with PHP. I am having trouble authenticating to the API. The documentation is here.
Here is what I have so far
var webAddress = "https://xboxapi.com/v2/latest-xbox360-games";
var httpResponse = (new HttpClient().GetAsync(webAddress)).Result;
httpResponse.EnsureSuccessStatusCode();
var jsonResponse = httpResponse.Content.ReadAsStringAsync().Result;
I'm just not sure how to add the authentication header that they are using in PHP.
Any help would be appreciated.
To add a custom header (in this case X-AUTH), you need to send a custom HttpRequestMessage. For example:
var webAddress = "https://xboxapi.com/v2/latest-xbox360-games";
HttpClient client = new HttpClient();
HttpRequestMessage msg = new HttpRequestMessage(HttpMethod.Get, webAddress);
msg.Headers.Add('X-AUTH', 'your-auth-key-here');
HttpResponseMessage response = await client.SendAsync(msg);

HttpClient authentication header not getting sent

I'm trying to use an HttpClient for a third-party service that requires basic HTTP authentication. I am using the AuthenticationHeaderValue. Here is what I've come up with so far:
HttpRequestMessage<RequestType> request =
new HttpRequestMessage<RequestType>(
new RequestType("third-party-vendor-action"),
MediaTypeHeaderValue.Parse("application/xml"));
request.Headers.Authorization = new AuthenticationHeaderValue(
"Basic", Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(
string.Format("{0}:{1}", "username", "password"))));
var task = client.PostAsync(Uri, request.Content);
ResponseType response = task.ContinueWith(
t =>
{
return t.Result.Content.ReadAsAsync<ResponseType>();
}).Unwrap().Result;
It looks like the POST action works fine, but I don't get back the data I expect. Through some trial and error, and ultimately using Fiddler to sniff the raw traffic, I discovered the authorization header isn't being sent.
I've seen this, but I think I've got the authentication scheme specified as a part of the AuthenticationHeaderValue constructor.
Is there something I've missed?
Your code looks like it should work - I remember running into a similar problem setting the Authorization headers and solved by doing a Headers.Add() instead of setting it:
request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(string.Format("{0}:{1}", "username", "password"))));
UPDATE:
It looks like when you do a request.Content, not all headers are being reflected in the content object. You can see this by inspecting request.Headers vs request.Content.Headers. One thing you might want to try is to use SendAsync instead of PostAsync. For example:
HttpRequestMessage<RequestType> request =
new HttpRequestMessage<RequestType>(
new RequestType("third-party-vendor-action"),
MediaTypeHeaderValue.Parse("application/xml"));
request.Headers.Authorization =
new AuthenticationHeaderValue(
"Basic",
Convert.ToBase64String(
System.Text.ASCIIEncoding.ASCII.GetBytes(
string.Format("{0}:{1}", "username", "password"))));
request.Method = HttpMethod.Post;
request.RequestUri = Uri;
var task = client.SendAsync(request);
ResponseType response = task.ContinueWith(
t =>
{ return t.Result.Content.ReadAsAsync<ResponseType>(); })
.Unwrap().Result;
This would also work and you wouldn't have to deal with the base64 string conversions:
var handler = new HttpClientHandler();
handler.Credentials = new System.Net.NetworkCredential("username", "password");
var client = new HttpClient(handler);
...
Try setting the header on the client:
DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes(String.Format("{0}:{1}", userName, password))));
This works for me.
Also, consider that Redirect-Handler will clear the Authorization header if your request gets redirected.
So if you call an HTTP endpoint and it redirected to the HTTPS one, you will lose your authorization header.
request.Headers.Authorization = null;
Framework: .NET v6.0
Actually your problem is with PostAsync- you should use SendAsync. In your code - client.PostAsync(Uri, request.Content); sends only the content the request message headers are not included.
The proper way is:
HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Post, url)
{
Content = content
};
message.Headers.Authorization = new AuthenticationHeaderValue("Basic", credentials);
httpClient.SendAsync(message);

Categories