Make Https call using HttpClient
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);
Make HTTPS call through HttpClient with client certificate that does not have access to private key
Is it possible to send client certificate without (access to) private key in HTTPs request (e.g. by using HttpClient)?
You can send it as content, sure; but you cannot use it as a client certificate without the private key. It would be like logging in to a system by just asserting a username.
The technical reason is that whenever certificates are sent in TLS there's also a required signature that has to be sent to prove that the private key is held by the sender. If the signature doesn't validate, then the recipient terminates the session.
Posting a dictionary as data to HTTPS server in C# using HTTPClient
Try using this approach, it works with the server I am sending data to.
var content = new StringContent("{some:json}");
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
client.DefaultRequestHeaders.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json;"));
HttpResponseMessage response = await client.PostAsync("https://SERVER_ADRESS", content);
I suspect the request header is the reason, and send StringContent
instead of FormUrlEncodedContent
HTTPS request fails using HttpClient
According to this SO post, you must enable TLS1.2 with ServicePointManager.
System.Net.ServicePointManager.SecurityProtocol |=
SecurityProtocolType.Tls12 |
SecurityProtocolType.Tls11 |
SecurityProtocolType.Tls; // comparable to modern browsers
Also noteworthy, the MSDN documentation for ServicePointManager.SecurityProtocols property makes this statement:
The .NET Framework 4.6 includes a new security feature that blocks
insecure cipher and hashing algorithms for connections.
which suggests that some form of SHA1 block might be in place.
EDIT 16 Sep 2020
I changed from the = assignment operator to the |= operator so that requests to any other legacy sites which still require SSL will continue to work.
Using HttpClient & HttpWebRequest for Https TLS1.2
You need to set the SecurityProtocol
property before calling WebRequest.Create
method.
Update:
Let me add some details that explain why this should be correct.
Having a look at the source code of WebRequest.Create(string)
method from referencesource.microsoft.com.
The return value is:
return Create(new Uri(requestUriString), false);
so now, Let's take a look at Create(Uri, bool)
method, it returns some object from WebRequestPrefixElement.Creator.Create(Uri)
.
Creator
is a property inside of WebRequestPrefixElement
and it's of type IWebRequestCreate
.
In your case, IWebRequestCreate
will be an HttpRequestCreator
object.
Looking at the code of HttpRequestCreator.Create
method:
public WebRequest Create( Uri Uri ) {
//
// Note, DNS permissions check will not happen on WebRequest
//
return new HttpWebRequest(Uri, null);
}
Finally, Let's look at that HttpWebRequest
constructor.
You'll see a long code there, but really what is important is this line:
SslProtocols = (SslProtocols)ServicePointManager.SecurityProtocol;
so the SecurityProtocol
value is assigned to a property called SslProtocols
.
So, it's obvious now that SecurityProtocol
is used and kind of saved to the HttpWebRequest object when you call Create
method, so changing SecurityProtocol
after calling Create
will not change the protocol used by the HttpWebRequest object.
Related Topics
How to Inject JavaScript in Webbrowser Control
Routing with Multiple Parameters Using ASP.NET MVC
Using Regex to Balance Match Parenthesis
Default Visibility for C# Classes and Members (Fields, Methods, etc.)
Order of Linq Extension Methods Does Not Affect Performance
Wpf Binding UI Events to Commands in Viewmodel
Does C# Have Extension Properties
ASP.NET MVC: No Parameterless Constructor Defined for This Object
Window VS Page VS Usercontrol for Wpf Navigation
Embedding JavaScript Engine into .Net
How to Get Object Size in Memory
How to Read a Specified Line in a Text File
"The Remote Certificate Is Invalid According to the Validation Procedure." Using Gmail Smtp Server
Which Tls Version Was Negotiated