I have a Windows 10 UWP application that uses WCF to make calls to our pre-existing service. The service was added to my project by adding it as a service reference, which then auto generated most of the code and the WCF client. Both the client and the service are running internally only. The service is running on an IIS server and has a self signed certificate. Because of that, we typically get a certificate error when we access or browse the service. That is fine and expected and frankly, we simply want to ignore it since we are internal only.
That said, in past applications (all written in .Net as well but with the full framework) we simply use the following code to setup the client.
public PacTracMobileServerClient GetClient()
{
try
{
AppConfig config = new AppConfig();
string url = config.GetODSServerAddress;
CustomBinding binding = new CustomBinding();
//TODO Make these timeouts configurable as well
binding.SendTimeout = TimeSpan.FromMinutes(10);
binding.ReceiveTimeout = TimeSpan.FromMinutes(10);
TextMessageEncodingBindingElement tme = new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8);
binding.Elements.Add(tme);
if (url.StartsWith("https", StringComparison.CurrentCultureIgnoreCase))
{
//HTTPS binding
HttpsTransportBindingElement https = new HttpsTransportBindingElement();
https.MaxReceivedMessageSize = int.MaxValue;
https.MaxBufferSize = int.MaxValue;
https.RequireClientCertificate = false;
binding.Elements.Add(https);
//Trust all certificates
ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };
}
else
{
//HTTP binding
HttpTransportBindingElement http = new HttpTransportBindingElement();
http.MaxReceivedMessageSize = int.MaxValue;
http.MaxBufferSize = int.MaxValue;
binding.Elements.Add(http);
}
var ODSUri = new System.Uri(url);
var endPoint = new EndpointAddress(ODSUri);
var client = new PacTracMobileServerClient(binding, endPoint);
return client;
}
catch (Exception ex)
{
return null;
}
}
The key to the above is the line:
ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };
I have confirmed that with our other existing, non Windows 10 UWP applications, that if I comment out that line, I get similar errors. If I leave it in, I can access the service just fine, without errors.
Therefore, I need something similar for Windows 10 UWP. However, the ServicePointManager namespace is not available in UWP. I have seen things like creating http filters which are then passed into an httpClient to ignore certificates but since I am using the generated WCF client, I don't have an httpClient.
I have been researching this alot but because we are Windows 10 UWP AND using WCF generated code, I can't seem to find a whole lot for this specific issue.
The one thing I did find that seemed promising and tried, did not work and that is:
public PacTracMobileServerClient GetClient()
{
try
{
AppConfig config = new AppConfig();
string url = config.GetODSServerAddress;
CustomBinding binding = new CustomBinding();
//TODO Make these timeouts configurable as well
binding.SendTimeout = TimeSpan.FromMinutes(10);
binding.ReceiveTimeout = TimeSpan.FromMinutes(10);
TextMessageEncodingBindingElement tme = new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8);
binding.Elements.Add(tme);
if (url.StartsWith("https", StringComparison.CurrentCultureIgnoreCase))
{
//HTTPS binding
HttpsTransportBindingElement https = new HttpsTransportBindingElement();
https.MaxReceivedMessageSize = int.MaxValue;
https.MaxBufferSize = int.MaxValue;
https.RequireClientCertificate = false;
binding.Elements.Add(https);
//Trust all certificates
//ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };
}
else
{
//HTTP binding
HttpTransportBindingElement http = new HttpTransportBindingElement();
http.MaxReceivedMessageSize = int.MaxValue;
http.MaxBufferSize = int.MaxValue;
binding.Elements.Add(http);
}
var ODSUri = new System.Uri(url);
var endPoint = new EndpointAddress(ODSUri);
var client = new PacTracMobileServerClient(binding, endPoint);
client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
return client;
}
catch (Exception ex)
{
return null;
}
}
Particularly where I do this:
client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
Note, the method above, GetClient, works fine in both cases and does return me a client. However, when I then actually try to call a WCF method against that client, I get an exception:
net_http_client_execution_error
UPDATE: I am trying to think outside the box here to find a solution to this. It seems I have found a hole that there is no fix for given the combination of UWP (.net core), WCF and SSL Client certificate. This has now cost me days, I spent all day researching today and thought I found something, however it still did not work. This is what I did, in the generated service reference code, I found the class that creates the client. I saw that it inherits from System.ServiceModel.ClientBase. So, I created this class:
public class MyCertificateValidator : X509CertificateValidator
{
public MyCertificateValidator()
{
}
public override void Validate(X509Certificate2 certificate)
{
}
}
I read that if the validate method returns, it is assumed that the certificate was validated. So, I left this method blank so that it would return. I then did this where my client is created
this.ChannelFactory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.Custom;
this.ChannelFactory.Credentials.ServiceCertificate.Authentication.CustomCertificateValidator = new MyCertificateValidator();
This seems like it should work but it doesn't. Any ideas with this?
I also looked into creating a wrapper class library in .Net classic and the class library itself works fine, because by having the full .Net framework, I can do this again:
ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };
However, when I build the .dll, I cannot reference it from my UWP application. When I try to add the reference, it says that referencing a .net framework library in a .net core app is not allowed.
Please help!!!
Thanks!