Search code examples
wcfwcf-bindingwcf-security

Keep getting WCF error despite making changes to web config and host factory


On my developer box, my WCF service works well with no problems, but when I deploy it on my shared server, I get the following error message when I try to access my service

https://www.mydomain.com/Admin/myservice/service.svc:

The service '/admin/myservice/service.svc' cannot be activated due to an exception during compilation. The exception message is: This collection already contains an address with scheme http. There can be at most one address per scheme in this collection. If your service is being hosted in IIS you can fix the problem by setting 'system.serviceModel/serviceHostingEnvironment/multipleSiteBindingsEnabled' to true or specifying 'system.serviceModel/serviceHostingEnvironment/baseAddressPrefixFilters'. Parameter name: item.; This collection already contains an address with scheme http. There can be at most one address per scheme in this collection. If your service is being hosted in IIS you can fix the problem by setting 'system.serviceModel/serviceHostingEnvironment/multipleSiteBindingsEnabled' to true or specifying 'system.serviceModel/serviceHostingEnvironment/baseAddressPrefixFilters'. Parameter name: item

Here's the pertinent web.config configuration:

<serviceHostingEnvironment aspNetCompatibilityEnabled="true">
    <baseAddressPrefixFilters>
        <add prefix="https://www.mydomain.com/"/>
    </baseAddressPrefixFilters>
</serviceHostingEnvironment> 

Here's my host factory code:

public class MyServiceServiceHostFactory : ServiceHostFactory
{
    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        ServiceHost serviceHost = null;

        serviceHost = CreateMyServiceServiceHost(baseAddresses);

        return serviceHost;
    }

    private static ServiceHost CreateMyServiceServiceHost(Uri[] baseAddresses)
    {
        // initialize service host
        ServiceHost serviceHost = new ServiceHost(typeof(OrderServices), baseAddresses);

        // create and add service endpoint binding using message and user name
        WSHttpContextBinding wsHttpContextEndpointBinding = new WSHttpContextBinding(SecurityMode.TransportWithMessageCredential);
        wsHttpContextEndpointBinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
        wsHttpContextEndpointBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
        wsHttpContextEndpointBinding.AllowCookies = true;

        // add meta data service
        ServiceMetadataBehavior metadataBehavior = new ServiceMetadataBehavior();
        metadataBehavior.HttpGetEnabled = false;
        metadataBehavior.HttpsGetEnabled = true;
        metadataBehavior.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;

        ServiceAuthorizationBehavior serviceAuthorizationBehavior =
        serviceHost.Description.Behaviors.Find<ServiceAuthorizationBehavior>();
        serviceAuthorizationBehavior.PrincipalPermissionMode = PrincipalPermissionMode.UseAspNetRoles;

        ServiceDebugBehavior serviceDebugBehavior =
        serviceHost.Description.Behaviors.Find<ServiceDebugBehavior>();
        serviceDebugBehavior.IncludeExceptionDetailInFaults = true;

        ServiceCredentials serviceCredentials = new ServiceCredentials();
        serviceCredentials.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
        serviceCredentials.UserNameAuthentication.CustomUserNamePasswordValidator =
            new MyServiceUserNamePasswordValidator((MyServiceMembershipProvider) Membership.Providers["MyServiceMembershipProvider"]);

        serviceHost.Description.Behaviors.Add(metadataBehavior);
        serviceHost.Description.Behaviors.Add(serviceCredentials);

        serviceHost.AddServiceEndpoint(typeof(IOrderServices), wsHttpContextEndpointBinding, "");

        // Add MEX endpoint
        serviceHost.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName, MetadataExchangeBindings.CreateMexHttpsBinding(), "mex");
        return serviceHost;
    }
}

Why am I getting this error? Every technical document says that I am doing things correctly according to the documentation. Could this be related to a problem with SSL or the host name issues? This has me stumped.


Solution

  • I found a solution although inadequate for now. If you're running .NET 4 and guaranteed to run it, you add the following configuration:

    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
    

    This should clear up the error. If you're not running .NET 4, you have to create a factory as I did, but you should create a service host and specify an address on the list. The address you pick isn't trivial. The wrong one could be an unwanted Url or worse the wrong scheme, resulting in other service errors. Ideally, you should construct your Url from the HttpContext and your desired scheme.

    Here's a trimmed down version:

    public class MyServiceHostFactory : System.ServiceModel.Activation.ServiceHostFactory
    {
        protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
        {                        
            ServiceHost host;
    
            // This solution is less than ideal because the Uri at baseAddresses[0] could be the wrong Url or
            // the  wrong scheme. 
            host = new ServiceHost(serviceType, baseAddresses[0]);
    
            // A better solution, is to use the incoming request Uri and pass it in like so:
            host = new ServiceHost(serviceType, *** construct the url from Http Context ***);
    
            return host;
        }
    }