Windows Forms
A set of .NET Framework managed libraries for developing graphical user interfaces.
1,927 questions
This browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
We are currently migrating our code from .NET 4.7.2 to NET 7 (.Net Core).
Everything has been moved forward except one project that has to consume another company’s WebApi rest web service.
When we were forced to interact with this company they were unable (or unwilling) to provide us sample code
on how to consume their service which required a Client Certificate.
The below scenario and code is not exactly how things are configured, but was simplified in order to post on this forum.
Setup:
We have a WebService and several WinForm apps that call the Vendor’s API.
We generate a self-signed certificate from any workstation/server that needs to call the vendor’s service.
The certificate is in the trusted root for the machine and current user, etc.
We export that certificate and physically give it to the vendor.
We then use the code at the bottom of this post on the box the certificate was generated from to call the vendor service.
Success Method 1:
If the Program is started with Admin permissions (Run as Administrator) on .Net4.7.2 it works.
Running without elevated permissions will cause it to fail.
Success Method 2:
The other successful path is to use the LoginUser "advapi32.dll" windows dll to impersonate an Admin account and run the request under the elevated permissions.
Both methods fail under .NET Core.
When we run the code in .Net Core we receive an “500 Internal Server” error and the below message (modified to remove company names):
An unexpected error occurred.\r\nSystem.Exception: Unable to GetCertificate
From: ggWeb.ggWebCrh ClientIP: xxx.xxx.xxx.xx\r\nSystem.Exception: X-ENV-SSL_CLIENT_CERTIFICATE
returned blank\r\n
at Vendor.ggWeb.ggWebCrh.GetCertificate(WebHeaderCollection phdr)\r\n
at Vendor.ggWeb.ggWebRsc.ExecuteBo(Int32 plngWebServiceKey, Boolean pblnTest, Stream pstmInput, ggMsgObj pmsgUrlParameters)\r\n
at Vendor.ggWeb.ggWebRsc.ExecuteBo(Int32 plngWebServiceKey, Boolean pblnTest, Stream pstmInput, ggMsgObj pmsgUrlParameters)"
As some articles suggested we exported to a password protected pfx. Both methods work on .NET 4.7.2.
In the ServerCertificateCustomValidationCallback event you can see the Vendor’s GlobalSign SSL certificate information.
We did find one interesting article shown below that we wondering could be connected:
https://learn.microsoft.com/en-us/dotnet/core/compatibility/aspnet-core/6.0/clientcertificate-doesnt-trigger-renegotiation
We have exhausted our searching and decided to reach out in the hopes that someone can help.
Thank you all in advance for any ideas, assistance, direction, etc.
Sample Code:
//********************************
//******* Using HttpClient *******
//********************************
System.Net.Http.HttpClient objClient = null;
System.Net.Http.HttpClientHandler objHandler = null;
objHandler = new System.Net.Http.HttpClientHandler();
objHandler.ClientCertificateOptions = System.Net.Http.ClientCertificateOption.Manual;
objHandler.SslProtocols = System.Security.Authentication.SslProtocols.Tls12;
objHandler.ClientCertificates.Add(new System.Security.Cryptography.X509Certificates.X509Certificate2(fncFileToByteArray("C:\\MyCert.cer"));
//objHandler.ClientCertificates.Add(new System.Security.Cryptography.X509Certificates.X509Certificate2(fncFileToByteArray("C:\\MYCert.pfx"), "MyPassword"));
objHandler.CheckCertificateRevocationList = false;
objHandler.ServerCertificateCustomValidationCallback +=
(sender2, certificate, chain, sslPolicyErrors) =>
{
return true;
};
objClient = new System.Net.Http.HttpClient(objHandler);
objClient.BaseAddress = new Uri("https://Vendor.com/Api/Endpoint");
objClient.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
objClient.Timeout = TimeSpan.FromSeconds(15);
System.Net.Http.HttpResponseMessage rmResponse = null;
rmResponse = objClient.GetAsync("?SomeQuery=12345").GetAwaiter().GetResult();
//if (!rmResponse.IsSuccessStatusCode)
System.String strResult = rmResponse.Content.ReadAsStringAsync().GetAwaiter().GetResult();
System.Net.HttpWebResponse wrResponse = null;
//******************************************
//******* Using Relegated WebRequest *******
//******************************************
System.String strUrl = txtUrl.Text;
System.Net.HttpWebRequest objWebRequest = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(“https://Vendor.com/Api/Endpoint?SomeQuery=12345”);
objWebRequest.Method = "GET";
objWebRequest.Accept = "application/json";
objWebRequest.CachePolicy = new System.Net.Cache.HttpRequestCachePolicy(System.Net.Cache.HttpRequestCacheLevel.NoCacheNoStore);
objWebRequest.ClientCertificates.Add(new System.Security.Cryptography.X509Certificates.X509Certificate(fncFileToByteArray("C:\\MyCert.cer")));
objWebRequest.ServerCertificateValidationCallback = delegate { return true; };
wrResponse = (System.Net.HttpWebResponse)objWebRequest.GetResponse();
if (wrResponse.StatusCode != System.Net.HttpStatusCode.OK)
{
throw new System.Net.WebException("Unknown Status Code Returned");
}
String strResponseStream = null;
using (var reader = new System.IO.StreamReader(wrResponse.GetResponseStream()))
{
strResponseStream = reader.ReadToEnd();
}
In order to consume the Vendor's WebApi rest web service in .NET Core, you can follow these steps:
1. Install the required NuGet packages:
- System.Net.Http: This package provides the necessary classes for interacting with HTTP services.
- System.Security.Cryptography.X509Certificates: This package provides classes for working with X.509 certificates.
2. Import the necessary namespaces at the top of your code file:
```csharp
using System.Net.Http;
using System.Security.Cryptography.X509Certificates;
HttpClient
object and specify the required settings:
HttpClientHandler handler = new HttpClientHandler();
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
handler.SslProtocols = System.Security.Authentication.SslProtocols.Tls12;
handler.ClientCertificates.Add(new X509Certificate2("C:\\MyCert.cer"));
HttpClient client = new HttpClient(handler);
client.BaseAddress = new Uri("https://Vendor.com/Api/Endpoint");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.Timeout = TimeSpan.FromSeconds(15);
HttpResponseMessage response = await client.GetAsync("?SomeQuery=12345");
if (response.IsSuccessStatusCode)
{
string result = await response.Content.ReadAsStringAsync();
// Process the response data
}
else
{
// Handle the error scenario
}
Note: Make sure to replace "C:\MyCert.cer" with the correct path to your certificate file. If you have a password-protected certificate (PFX), you can use the X509Certificate2
constructor overload with the password parameter.
By using the HttpClient
class, you can send HTTP requests to the Vendor's API and receive the responses. Make sure to handle any exceptions and error scenarios appropriately as per your application's requirements.
I was playing Minecraft and placed. A dog and it died immediately and I checked the files and I sw this