views:

964

answers:

4

I have a WCF service that is behind an enterprise-class firewall, which is doing both hostname and port translation, e.g.:

https://ws.address.com/Service.svc --> https://serv.internal.com:44000/Service.svc

The service is secured with SSL-128 and requires a client certificate.

Because the internal server name is not accessible from outside the firewall, we had to implement a ServiceHostFactory to translate the WSDL and XSD import references that WCF generates:

public class MyCustomFactory : ServiceHostFactory
    {
        protected override ServiceHost CreateServiceHost(
            Type serviceType, Uri[] baseAddresses)
        {
            MyCustomHost customServiceHost = 
                new MyCustomHost(serviceType, baseAddresses);

            return customServiceHost;
        }

        class MyCustomHost : ServiceHost
        {
            public MyCustomHost(Type serviceType, 
                params Uri[] baseAddresses)
                : base(serviceType, 
                    GetBaseAddresses(serviceType, baseAddresses))
            {                
            }

            protected override void ApplyConfiguration()
            {
                base.ApplyConfiguration();
            }

            private static Uri[] GetBaseAddresses(
                Type serviceType, params Uri[] baseAddresses)
            {
                UriBuilder newBaseAddress = new UriBuilder();
                newBaseAddress.Path = "/" + serviceType.ToString() + 
                    ".svc";

                // from config
                newBaseAddress.Host = 
                    MyCustomSettings.ServiceBaseAddress; 

                if (baseAddresses.Length > 0)
                {
                    newBaseAddress.Scheme = baseAddresses[0].Scheme;
                }

                return new Uri[] { newBaseAddress.Uri };
            }
        }
    }

Here's the problem with this: unless the service is hosted on the internal machine on the default SSL port of 443, we get the error:

No protocol binding matches the given address 'https://ws.address.com/Service.svc'. Protocol bindings are configured at the Site level in IIS or WAS configuration.

It appears, from tinkering, that if we change the internal server to host the service on 443, or configure the firewall to forward from 44000 to 44000, everything works. Those aren't options in our production environment, though.

Edit: Forgot to mention, we tried to use an IWsdlExportExtension to flatten the WSDL, but that caused severe problems with the proxy code generation in svcutil or VS2008, so we scrapped the idea.

Does anyone know any way around this? I'm pulling my hair out!

Thanks in advance!

+1  A: 

You may need to explicitly create your own Binding (i.e., ServiceModel.WSHttpBinding) and add a Service Endpoint (.AddServiceEndpoint(..) ) with that binding.

http://msdn.microsoft.com/en-us/library/system.servicemodel.servicehost.addserviceendpoint(VS.85).aspx

routeNpingme
A: 

Have you tried putting the ip port in the address (from the question it did not look like it was used everytime):

https://ws.address.com:44000/Service.svc

Another thing that it may be is, is WCF listening for https traffic on that port, see:

http://msdn.microsoft.com/en-us/library/ms733768.aspx

Shiraz Bhaiji
I think the point was, the live environment needs the firewall to forward requests for ws.address.com:443 through to an internal address serv.internal.com:44000
davewasthere
A: 

You shouldn't change the base addresses in the factory. Write an extension instead to modify the WSDL. This would be a "IWsdlExportExtension" and you wanna overwrite ExportEndpoint to modify the endpoint addresses. This will leave your service listening to the correct base address.

OR

If you don't wan to get started with a WSDL extension...move your existing code into the "CreateServiceHost" method and scratch your custom host! That is not very nice but should work.

Alex
A: 

You didn't mention your host. IIS/WAS? If so, you may need to add the external host name to IIS config to the secure bindings list.

here is some information on changing the host-name in IIS hosted service

here is the command-line:

cscript //nologo %systemdrive%\inetpub\adminscripts\adsutil.vbs 
set W3SVC/1/SecureBindings  "10.(internal addr).1:443:ws.address.com"
"127.0.0.1:443:Internal Host name"

If that doesn't take care of it I'd go with "routeNpingme" and suggest you just need to get the endpoints specified correctly, using a binding that specifies your https ports and names. I think you can do this with existing binding options... but you may need to create a custom.

DanO