Make Https call using HttpClient
I have been using HttpClient
for making WebApi calls using C#. Seems neat & fast way compared to WebClient
. However I am stuck up while making Https
calls.
How can I make below code to make Https
calls?
HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = new Uri("https://foobar.com/");
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/xml"));
var task = httpClient.PostAsXmlAsync<DeviceRequest>(
"api/SaveData", request);
EDIT 1: The code above works fine for making http calls. But when I change the scheme to https it does not work. Here is the error obtained:
The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.
EDIT 2: Changing the scheme to https is: step one.
How do I supply certificate & public / private key along with C# request.
If the server only supports higher TLS version like TLS 1.2 only, it will still fail unless your client PC is configured to use higher TLS version by default. To overcome this problem, add the following in your code:
System.Net.ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
Modifying your code example, it would be
HttpClient httpClient = new HttpClient();
//specify to use TLS 1.2 as default connection
System.Net.ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
httpClient.BaseAddress = new Uri("https://foobar.com/");
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
var task = httpClient.PostAsXmlAsync<DeviceRequest>("api/SaveData", request);
Simply specify HTTPS in the URI.
new Uri("https://foobar.com/");
Foobar.com will need to have a trusted SSL cert or your calls will fail with untrusted error.
EDIT Answer: ClientCertificates with HttpClient
WebRequestHandler handler = new WebRequestHandler();
X509Certificate2 certificate = GetMyX509Certificate();
handler.ClientCertificates.Add(certificate);
HttpClient client = new HttpClient(handler);
EDIT Answer2: If the server you are connecting to has disabled SSL, TLS 1.0, and 1.1 and you are still running .NET framework 4.5(or below) you need to make a choice
- Upgrade to .Net 4.6+ (Supports TLS 1.2 by default)
- Add registry changes to instruct 4.5 to connect over TLS1.2 ( See: salesforce writeup for compat and keys to change OR checkout IISCrypto see Ronald Ramos answer comments)
- Add application code to manually configure .NET to connect over TLS1.2 (see Ronald Ramos answer)
There is a non-global setting at the level of HttpClientHandler
:
var handler = new HttpClientHandler()
{
SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls
};
var client = new HttpClient(handler);
Thus one enables latest TLS versions.
Note, that the default value SslProtocols.Default
is actually SslProtocols.Ssl3 | SslProtocols.Tls
(checked for .Net Core 2.1 and .Net Framework 4.7.1).
Update: In .Net 5.0 the default value for HttpClientHandler.SslProtocols
is None
whcih means the following (see docs):
Allows the operating system to choose the best protocol to use, and to block protocols that are not secure. Unless your app has a specific reason not to, you should use this field.