简体   繁体   中英

Dynamically Bind WCF Endpoints To HTTPS Based on IIS Bindings

I have an WCF service that I am converting from HTTP to HTTPS. Clients currently have a hardcoded HTTP URL to this service. The server binds the service using some custom behaviors in the Web.config file:

  <service behaviorConfiguration="MyServiceBehaviors" name="MyService">
    <endpoint address="" behaviorConfiguration="MyEndpointBehaviors" binding="customBinding" bindingConfiguration="MyHttpCustomBinding" name="MyService" contract="IMyService" />
  </service>

I want to bind the WCF service to HTTP and HTTPS. I can do this with two entries in the Web.config file:

  <service behaviorConfiguration="MyServiceBehaviors" name="MyService">
    <endpoint address="" behaviorConfiguration="MyEndpointBehaviors" binding="customBinding" bindingConfiguration="MyHttpCustomBinding" name="MyService" contract="IMyService" />
    <endpoint address="" behaviorConfiguration="MyEndpointBehaviors" binding="customBinding" bindingConfiguration="MyHttpsCustomBinding" name="MyService" contract="IMyService" />
  </service>

I also have a requirement that the server may not have HTTPS enabled at first. So IIS may not be bound to HTTPS port 443 at the time the WCF service is activated.

If IIS is not bound to HTTPS, and the Web.config binds to both endpoints like the above example, and a client tries to activate the service on the HTTP endpoint, the service fails to start with the following activation exception:

WebHost failed to process a request. Sender Information: System.ServiceModel.ServiceHostingEnvironment+HostingManager/45653674 Exception: System.ServiceModel.ServiceActivationException: The service '/MyApp/MyService.svc' cannot be activated due to an exception during compilation. The exception message is: Could not find a base address that matches scheme https for the endpoint with binding CustomBinding. Registered base address schemes are [http].

I think the WCF service needs to bind to HTTPS only when HTTPS is enabled in IIS. I don't see a way to accomplish this in the Web.config file, so I assume I will need to do some dynamic server binding.

How can I selectively bind the HTTP and HTTPS endpoints in WCF based on IIS configuration?

I also don't see a way the service could be notified if the IIS binding changes to add/remove HTTPS, but I am OK with asking admins to recycle the application pool/IISRESET/reboot to get the service to use the updated settings.

I was able to get this to work with the following steps:

Add a Factory attribute to the MyService.svc file that will be able to construct the service:

<%@ ServiceHost Language="C#" Debug="true"
    Service="MyService"
    Factory="MyServiceFactory" %>

Create the factory class in the WCF service DLL:

public class MyServiceFactory : ServiceHostFactory
{
    public override ServiceHostBase CreateServiceHost(string service, Uri[] baseAddresses)
    {
        return CreateServiceHost(typeof(MyService), baseAddresses);
    }

    protected override ServiceHost CreateServiceHost(Type t, Uri[] baseAddresses)
    {
        var serviceHost = new ServiceHost(t, baseAddresses);
        foreach (Uri address in baseAddresses)
        {
            bool secure = false;
            if (address.Scheme == "https")
                secure = true;

            var binding = GetMyCustomBinding(secure);
            var endpoint = serviceHost.AddServiceEndpoint(typeof(IMyService), binding, address);

            endpoint.Behaviors.Add(new MyEndpointBehavior());
        }

        return serviceHost;
    }
}

The given array of baseAddresses include the endpoint Uris to which IIS is bound. For each endpoint, bind the service to the endpoint using a custom binding. If the endpoint is "https", then use a secure binding; otherwise, use a standard binding.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM