none
WinService hosting WCF design with SSL?

    問題

  • Hi,

    I had a general question about the behavior when using a Windows Service to host a set of WCF Services in regards to using SSL.  So I have a small POC made as a console project that hosts a set of both http and https services.  As well as a small console client to test these -  all works fine.  I also created and deployed a windows service to my machine.  Now the http service binding can be found and consumed by the console client when I try to create the service proxy, but the https services give me this error (which I have seen before and know what it means):

    There was an error downloading 'https://localhost:8101/WCF/Services'.

    The underlying connection was closed: An unexpected error occurred on a send.
    Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
    An existing connection was forcibly closed by the remote host
    Metadata contains a reference that cannot be resolved: 'https://localhost:8101/WCF/Services'.
    An error occurred while making the HTTP request to https://localhost:8101/WCF/Services. This could be due to the fact that the server certificate is not configured properly with HTTP.SYS in the HTTPS case. This could also be caused by a mismatch of the security binding between the client and the server.
    The underlying connection was closed: An unexpected error occurred on a send.
    Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
    An existing connection was forcibly closed by the remote host
    If the service is defined in the current solution, try building the solution and adding the service reference again.


    So...I went into IIS, added an https binding on that port and attached the certificate, and presto it worked.  My question is why does a windows service rely on needing the certificate registered in IIS since it is not even being hosted by IIS?  Is there something I can add in code to get around needing to use IIS for the certificate registration?

    Here is some of my setup code for the WinService.  This is the same code used in my console service that works fine:

            public ServiceProfile Profile { get; set; }
            WSHttpBinding Binding { get; set; }
            ServiceHost Host { get; set; }
            ServiceMetadataBehavior MetaData { get; set; }
    ...
    
            private void BindService(ServiceProfile sp)
            {
                Binding = new WSHttpBinding();
                MetaData = new ServiceMetadataBehavior();
    
                // If we are attaching a SSL certificate
                if (sp.X509CertIssuedTo.Length >= sp.MinCertLength)
                {
                    MetaData.HttpsGetEnabled = true;
                    MetaData.HttpsGetUrl = new Uri(sp.Uri);
                }
                else
                {
                    MetaData.HttpGetEnabled = (sp.X509CertIssuedTo.Length < sp.MinCertLength);
                    MetaData.HttpGetUrl = new Uri(sp.Uri);
                } 
                Binding.Security.Mode = sp.SecMode;
                Binding.Security.Transport.ClientCredentialType = sp.CredentialType;
               
                switch (sp.Name.ToUpper())
                {
                    case "CALCULATOR":
                        Host = new ServiceHost(typeof(Calculator), new Uri(sp.Uri));
    
                        // Accept a username and password credential
                        if (sp.CredentialType == HttpClientCredentialType.Basic)
                        {
    
                            Binding.Security.Message.EstablishSecurityContext = false;
                            Binding.Security.Message.NegotiateServiceCredential = false;
                            Binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
                            Host.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
                            Host.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = new UserPassValidator();
                        }
    
                        Host.AddServiceEndpoint(typeof(Calculator), Binding, sp.Uri.ToLower());
                        break;
    
                    case "EDITOR":
                        break;
    
                    default:
                        break;
                }
    
                // If SSL needs to be enabled, bind the specified SSL certificate to the service
                if ( (sp.SecMode == SecurityMode.Transport) || (sp.SecMode == SecurityMode.TransportWithMessageCredential) )
                {
                    Host.Credentials.ServiceCertificate.SetCertificate( StoreLocation.LocalMachine,
                                                                        StoreName.Root,
                                                                        X509FindType.FindBySubjectName,
                                                                        sp.X509CertIssuedTo);
                }
               
                Host.Description.Behaviors.Remove(Host.Description.Behaviors[2]);
                Host.Description.Behaviors.Add(MetaData);
            }

     


    My Blog: http://www.montavesta.net


    2012年3月16日 下午 08:51

解答

  • Hello, the above code tells the service to use a particular certificate in the local certificate store. But it doesn't install the certificate. So you need to make sure the certificate is correctly installed. In addition, unless your service runs as administrator, you need to use netsh to grant the service privilege to listen on the specific port: http://msdn.microsoft.com/en-us/library/ms733791.aspx.

    Lante, shanaolanxing This posting is provided "AS IS" with no warranties, and confers no rights.
    If you have feedback about forum business, please contact msdnmg@microsoft.com. But please do not ask technical questions in the email.

    • 已提議為解答 Dragan Radovac 2012年3月18日 下午 12:48
    • 已標示為解答 Yi-Lun Luo 2012年3月23日 上午 11:48
    2012年3月18日 上午 11:53

所有回覆

  • You don't need to use IIS, but you do need to install the certificate on your system.  IIS does this for you - which is why it started working.

    You can refer to this article for details on how to manually install the certificate (without using IIS) here: http://www.codeproject.com/Articles/24027/SSL-with-Self-hosted-WCF-Service


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".

    2012年3月16日 下午 08:57
  • You don't need to use IIS, but you do need to install the certificate on your system.  IIS does this for you - which is why it started working.

    Doesn't this set the cert?

    Host.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.Root, X509FindType.FindBySubjectName, sp.X509CertIssuedTo);

    Is there a way to bind the cert to a specific port in C#?


    My Blog: http://www.montavesta.net




    2012年3月16日 下午 09:05
  • Hello, the above code tells the service to use a particular certificate in the local certificate store. But it doesn't install the certificate. So you need to make sure the certificate is correctly installed. In addition, unless your service runs as administrator, you need to use netsh to grant the service privilege to listen on the specific port: http://msdn.microsoft.com/en-us/library/ms733791.aspx.

    Lante, shanaolanxing This posting is provided "AS IS" with no warranties, and confers no rights.
    If you have feedback about forum business, please contact msdnmg@microsoft.com. But please do not ask technical questions in the email.

    • 已提議為解答 Dragan Radovac 2012年3月18日 下午 12:48
    • 已標示為解答 Yi-Lun Luo 2012年3月23日 上午 11:48
    2012年3月18日 上午 11:53