locked
Self hosted wcf https works only when iis has a site w https binding RRS feed

  • Question

  • I have a self hosted wcf service, windws 10, iis 10

    The WCF service can listen on https://...:443 only if iis also has a site bound to 443

    If I stop the IIS site bound to 443, my self hosted WCF service can no longer be connected to by a client

    I have a GoDaddy cert in the local machine store
    I made and ran the following .bat file

    set certHash=0102030405060708090a0102030405060708090a
    set appId=b1a09058-9bc1-46b6-9cbb-15d79280bcd3
    set port=443
    netsh http add sslcert ipport=0.0.0.0:%port% certhash=%certHash% appid={%appId%} 
    netsh http add urlacl url=https://+:443/MyWCFService/ user=everyone

    Wednesday, May 1, 2019 6:08 PM

Answers

  • Hi Bill,
    The issue boils down to that we need to bind a certificate to the specific port. otherwise, it is not able to secure https communication. Your idea is good, no problem, use the NETSH HTTP command to bind a certificate to the specific port. there might something amiss with the transferred parameter the command seems to me.
    I have made a demo, which using a console application to host the service. wish it is useful to you.
    Server(console application)

    class Program
        {
            /// <summary>
            /// WCF https binding.
            /// </summary>
            /// <param name="args"></param>
            static void Main(string[] args)
            {
                Uri uri = new Uri("https://localhost:4386");
                WSHttpBinding binding = new WSHttpBinding();
                binding.Security.Mode = SecurityMode.Transport;
                binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
                using (ServiceHost sh = new ServiceHost(typeof(TestService), uri))
                {
                    sh.AddServiceEndpoint(typeof(ITestService), binding, "");
                    ServiceMetadataBehavior smb;
                    smb = sh.Description.Behaviors.Find<ServiceMetadataBehavior>();
                    if (smb == null)
                    {
                        smb = new ServiceMetadataBehavior()
                        {
                            HttpsGetEnabled = true
                        };
                        sh.Description.Behaviors.Add(smb);
    
                    }
                    Binding mexbinding = MetadataExchangeBindings.CreateMexHttpsBinding();
                    sh.AddServiceEndpoint(typeof(IMetadataExchange), mexbinding, "mex");
    
                    sh.Opened += delegate
                    {
                        Console.WriteLine("service is ready");
                    };
                    sh.Closed += delegate
                    {
                        Console.WriteLine("service is closed");
                    };
                    sh.Open();
                    Console.ReadLine();
    
                    sh.Close();
                }
            }
        }
        [ServiceContract]
        public interface ITestService
        {
            [OperationContract]
            string GetResult();
        }
    
        [ServiceBehavior]
        public class TestService : ITestService
        {
            public string GetResult()
            {
                return $"Hello, busy World. {DateTime.Now.ToShortTimeString()}";
            }
    }
    

    Binding a SSL certificate to the port (execute the CMD with administrator privilege)

    netsh http add sslcert ipport=0.0.0.0:4386 certhash=cbc81f77ed01a9784a12483030ccd497f01be71c appid={66011568-BCFB-41AE-929D-BEE3366E6B67}

    In the above command, the ipport parameter is the port number to be bound. Certhash parameter is the thumbprint of the certificate, and by default, we need to specify the certificate store in the local machine(Certlm.msc), the appid parameter is the GUID that identifies your console application. usually in the CSPROJ file (Open it with notepad application, we will find it).
    For details, refer to the following document.
    https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-configure-a-port-with-an-ssl-certificate

    Client (invocation by adding service reference)

    static void Main(string[] args)
            {
    
                //for validating the self-signed certificate.
                ServicePointManager.ServerCertificateValidationCallback += delegate
                {
                    return true;
                };
                ServiceReference1.TestServiceClient client = new ServiceReference1.TestServiceClient();
                try
                {
                    var result = client.GetResult();
                    Console.WriteLine(result);
                }
                catch (Exception)
                {
    
                    throw;
                }
    
    

    Result.
    https://i.stack.imgur.com/Tthtq.png
    Feel free to let me know if there is anything I can help with.
    Best Regards
    Abraham

    Friday, May 3, 2019 2:21 AM

All replies

  • Hi Bill,
    For hosting a WCF service using https binding, we usually use transport security and add a https binding in IIS site binding module. The WCF project template is WCF service application.
    https://i.stack.imgur.com/ZB3iG.png
    As for binding a certificate to the corresponding port, it is usually completed by the IIS.
    Please refer to the following document.
    https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-configure-an-iis-hosted-wcf-service-with-ssl
    For self-hosting Console application, we need to bind the certificate to the port with NETSH command, as you showed in your post.
    https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-configure-a-port-with-an-ssl-certificate
    Feel free to let me know if there is anything I can help with.
    Best Regards
    Abraham
    Thursday, May 2, 2019 2:24 AM
  • Thanks Abraham

    I did those things, and my console wcf service works as long as any site in IIS is bound to 443
    So I know the transport settings in the .config are good
    My goal is to have the WCF be able to run on a machine not running IIS
    So I bound the cert to 443, but the WCF cant connect unless I bind a site in IIS

    Thursday, May 2, 2019 12:14 PM
  • Hi Bill,
    The issue boils down to that we need to bind a certificate to the specific port. otherwise, it is not able to secure https communication. Your idea is good, no problem, use the NETSH HTTP command to bind a certificate to the specific port. there might something amiss with the transferred parameter the command seems to me.
    I have made a demo, which using a console application to host the service. wish it is useful to you.
    Server(console application)

    class Program
        {
            /// <summary>
            /// WCF https binding.
            /// </summary>
            /// <param name="args"></param>
            static void Main(string[] args)
            {
                Uri uri = new Uri("https://localhost:4386");
                WSHttpBinding binding = new WSHttpBinding();
                binding.Security.Mode = SecurityMode.Transport;
                binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
                using (ServiceHost sh = new ServiceHost(typeof(TestService), uri))
                {
                    sh.AddServiceEndpoint(typeof(ITestService), binding, "");
                    ServiceMetadataBehavior smb;
                    smb = sh.Description.Behaviors.Find<ServiceMetadataBehavior>();
                    if (smb == null)
                    {
                        smb = new ServiceMetadataBehavior()
                        {
                            HttpsGetEnabled = true
                        };
                        sh.Description.Behaviors.Add(smb);
    
                    }
                    Binding mexbinding = MetadataExchangeBindings.CreateMexHttpsBinding();
                    sh.AddServiceEndpoint(typeof(IMetadataExchange), mexbinding, "mex");
    
                    sh.Opened += delegate
                    {
                        Console.WriteLine("service is ready");
                    };
                    sh.Closed += delegate
                    {
                        Console.WriteLine("service is closed");
                    };
                    sh.Open();
                    Console.ReadLine();
    
                    sh.Close();
                }
            }
        }
        [ServiceContract]
        public interface ITestService
        {
            [OperationContract]
            string GetResult();
        }
    
        [ServiceBehavior]
        public class TestService : ITestService
        {
            public string GetResult()
            {
                return $"Hello, busy World. {DateTime.Now.ToShortTimeString()}";
            }
    }
    

    Binding a SSL certificate to the port (execute the CMD with administrator privilege)

    netsh http add sslcert ipport=0.0.0.0:4386 certhash=cbc81f77ed01a9784a12483030ccd497f01be71c appid={66011568-BCFB-41AE-929D-BEE3366E6B67}

    In the above command, the ipport parameter is the port number to be bound. Certhash parameter is the thumbprint of the certificate, and by default, we need to specify the certificate store in the local machine(Certlm.msc), the appid parameter is the GUID that identifies your console application. usually in the CSPROJ file (Open it with notepad application, we will find it).
    For details, refer to the following document.
    https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-configure-a-port-with-an-ssl-certificate

    Client (invocation by adding service reference)

    static void Main(string[] args)
            {
    
                //for validating the self-signed certificate.
                ServicePointManager.ServerCertificateValidationCallback += delegate
                {
                    return true;
                };
                ServiceReference1.TestServiceClient client = new ServiceReference1.TestServiceClient();
                try
                {
                    var result = client.GetResult();
                    Console.WriteLine(result);
                }
                catch (Exception)
                {
    
                    throw;
                }
    
    

    Result.
    https://i.stack.imgur.com/Tthtq.png
    Feel free to let me know if there is anything I can help with.
    Best Regards
    Abraham

    Friday, May 3, 2019 2:21 AM