基于 IIS 绑定将 WCF 端点动态绑定到 HTTPS

Dynamically Bind WCF Endpoints To HTTPS Based on IIS Bindings

我有一个正在从 HTTP 转换为 HTTPS 的 WCF 服务。客户端目前有一个硬编码的 HTTP URL 到此服务。服务器使用 Web.config 文件中的一些自定义行为绑定服务:

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

我想将 WCF 服务绑定到 HTTP 和 HTTPS。我可以用 Web.config 文件中的两个条目来做到这一点:

  <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>

我还有一个要求,就是服务器一开始不能开启HTTPS。所以在激活WCF服务时IIS可能没有绑定到HTTPS端口443。

如果 IIS 绑定到 HTTPS,并且 Web.config 像上面的示例一样绑定到两个端点,并且客户端尝试激活 HTTP 上的服务终结点,服务无法启动并出现以下激活异常:

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].

我认为只有在 IIS 中启用 HTTPS 时,WCF 服务才需要绑定到 HTTPS。我没有在 Web.config 文件中看到完成此操作的方法,因此我假设我需要进行一些动态服务器绑定。

如何根据 IIS 配置在 WCF 中有选择地绑定 HTTP 和 HTTPS 端点?

如果 IIS 绑定更改为 add/remove HTTPS,我也看不到可以通知服务的方式,但我同意要求管理员回收应用程序 pool/IISRESET/reboot 以获得服务以使用更新的设置。

我能够通过以下步骤让它工作:

将工厂属性添加到 MyService.svc 将能够构建服务的文件:

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

在 WCF 服务 DLL 中创建工厂 class:

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;
    }
}

给定的 baseAddress 数组包括 IIS 绑定到的端点 Uris。对于每个端点,使用自定义绑定将服务绑定到端点。如果端点是 "https",则使用安全绑定;否则,使用标准绑定。