Search code examples
.netwcfiishttps

WCF Error when trying to set up service to listen on http and https


I have two WCF services to which my apps connect. One is older and http protocol. The other is newer and https. They played well together until now.

However, I now find my older service being blocked by BitDefender and other endpoint protection because it is http. So I am trying to get the old service to use https, but to remain backward compatible to previous patch levels that still use http. So what I did was to convert the older server -- which I will call Walrus -- to listen to both http and https. Both older and newer services are coded in .NET and run on IIS 10. on the same machine, but listening to different URLs.

However, when I install the config for the older service to listen on https, the newer service breaks with this message:

There was no endpoint listening at https://cloudbackups.mycompany.net/cumulus.svc/cumulus.svc/PCBA that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details.

and the inner exception message reads:

The remote server returned an error: (404) Not Found.

If I revert to the previous config, there is no problem. And I am beyond confused.

Web.config for the older WCF:

<?xml version="1.0"?>
<configuration>
    <!-- Services Configuration over HTTP and HTTPS -->
    <connectionStrings configSource="connectionstrings.config"/>
    <!--
    For a description of web.config changes see http://go.microsoft.com/fwlink/?LinkId=235367.

    The following attributes can be set on the <httpRuntime> tag.
      <system.Web>
        <httpRuntime targetFramework="4.5" />
      </system.Web>
  -->
    <system.web>
        <compilation debug="true" strict="false" explicit="true" targetFramework="4.7.2"/>
        <pages controlRenderingCompatibilityVersion="4.0"/>
    </system.web>
    <system.webServer>
        <modules runAllManagedModulesForAllRequests="true"/>
        <!--
        To browse web app root directory during debugging, set the value below to true.
        Set to false before deployment to avoid disclosing web app folder information.
      -->
        <directoryBrowse enabled="true"/>
    </system.webServer>
    <system.serviceModel>
        <behaviors>
            <serviceBehaviors>
                <behavior name="ServiceBehavior">
                    <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <bindings>
            <basicHttpBinding>
                <binding name="Basic">
                    <security mode="None" />
                </binding>
            </basicHttpBinding>
            <wsHttpBinding>
                <binding name="WsPBinder">
                    <security mode="None" />
                </binding>
            </wsHttpBinding>
            <sslbinding>
                <binding name="HttpsBinding">
                    <security mode="Transport" />
                </binding>
            </sslbinding>
            <wssecurebinding>
                <binding name="wsHttpsBinding">
                    <security mode="Transport" />
                </binding>
            </wssecurebinding>
        </bindings>
        <services>
            <service behaviorConfiguration="ServiceBehavior" name="PedFastRemoteServices.PedFastRemoteServices">
                <endpoint address="http://services.mycompany.net/Walrus.svc/BA" 
                          binding="basicHttpBinding" 
                          bindingConfiguration="Basic" 
                          contract="Walrus.PTRemote"/>
                <endpoint address="https://services.mycompany.net/Walrus.svc/BA" 
                          binding="basicHttpBinding" 
                          bindingConfiguration="sslbinding" 
                          contract="Walrus.PTRemote"/>
            </service>
        </services>
    </system.serviceModel>
    <runtime>
        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
            <dependentAssembly>
                <assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
            </dependentAssembly>
            <dependentAssembly>
                <assemblyIdentity name="System.Threading.Tasks" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
            </dependentAssembly>
            <dependentAssembly>
                <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
            </dependentAssembly>
        </assemblyBinding>
    </runtime>
</configuration>

And the server config for the newer WCF:

<?xml version="1.0" encoding="utf-8"?>
<!-- PedGuard Configuration over HTTPS -->
<configuration>
    <connectionStrings configSource="connectionStrings.config" />
    <appSettings>
        <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
    </appSettings>
    <system.web>
        <customErrors mode="Off"/>
        <compilation debug="true" targetFramework="4.7.2" />
        <httpRuntime targetFramework="4.7.2" />
    </system.web>
    <system.serviceModel>
        <behaviors>
            <serviceBehaviors>
                <behavior name="ServiceBehavior">
                    <serviceMetadata httpsGetEnabled="true" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <bindings>
            <basicHttpBinding>
                <binding name="Basic" />
            </basicHttpBinding>
        </bindings>
        <services>
            <service behaviorConfiguration="ServiceBehavior" name="PTBackupServices.PedFastBackup">
                <endpoint address="/cumulus.svc/PCBA" 
                          binding="basicHttpBinding" 
                          bindingConfiguration="Basic" 
                          name="PCBA" 
                          contract="cumulus.iPTPEDBackup" />
            </service>
        </services>
        <protocolMapping>
            <add binding="basicHttpBinding" scheme="https" />
        </protocolMapping>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="false" />
    </system.serviceModel>
    <system.webServer>
        <modules runAllManagedModulesForAllRequests="true" />
        <!--
        To browse web app root directory during debugging, set the value below to true.
        Set to false before deployment to avoid disclosing web app folder information.
      -->
        <directoryBrowse enabled="false" />
    </system.webServer>
</configuration>
<!--ProjectGuid: D9EFA79D-236B-4FAA-9C45-B7A61C485DF5-->

And finally the client-side config:

<system.serviceModel>
  <bindings>
   <basicHttpBinding>
    <binding name="BA" />
    <binding name="PCBA">
     <security mode="Transport" />
    </binding>
   </basicHttpBinding>
   <wsHttpBinding>
    <binding name="WsPlain" />
   </wsHttpBinding>
  </bindings>
  <client>
   <endpoint address="http://services.mycompany.net/Walrus.svc/BA"
    binding="basicHttpBinding" bindingConfiguration="BA" contract="Walrus.PTRemote"
    name="BA" />
   <endpoint address="http://services.mycompany.net/Walrus.svc/WsPlain"
    binding="wsHttpBinding" bindingConfiguration="WsPlain" contract="Walrus.PTRemote"
    name="WsPlain">
    <identity>
     <servicePrincipalName value="host/PF2WebMaster" />
    </identity>
   </endpoint>
   <endpoint address="https://CloudBackups.mycompany.net/cumulus.svc/cumulus.svc/PCBA"
    binding="basicHttpBinding" bindingConfiguration="PCBA" contract="cumulus.iPTPEDBackup"
    name="PCBA" />
  </client>
 </system.serviceModel>

Solution

  • Issues discovered and worked.

    1. It is not possible for two WCF services to be listening on 443 of the same machine. So I provisioned one WCF service to another server.

    2. The web.config also has to have one listener name for HTTP and another for HTTPS. to that end, the web.config looks like this:

        <system.serviceModel>
            <bindings>
                <basicHttpBinding>
                    <binding name="BA">
                        <security mode="None" />
                    </binding>
                    <binding name="HttpsBinding">
                        <security mode="Transport" />
                    </binding>
                    <binding name="PCBA">
                        <security mode="Transport" />
                    </binding>
                </basicHttpBinding>
                <wsHttpBinding>
                    <binding name="WsPlain" />
                </wsHttpBinding>
            </bindings>
            <client>
                <endpoint address="http://Walrus.mycompany.net/PedFastRemoteServices.svc/BA"
                          binding="basicHttpBinding"
                          bindingConfiguration="BA"
                          contract="Walrus.PTRemote"
                          name="BA" />
                <endpoint address="https://Walrus.mycompany.net/PedFastRemoteServices.svc/secure"
                          binding="basicHttpBinding"
                          bindingConfiguration="HttpsBinding"
                          contract="Walrus.PTRemote"
                          name="secure" />
            </client>
        </system.serviceModel>
    

    with a matching serviceModel section in the client app.config that also includes the cumulus reference.