Add the following attribute to your service class:
<ServiceBehavior(AddressFilterMode:=AddressFilterMode.Any)>
This allows the service to be addressed by the client as https://...
but the service can still be hosted on http://.....
See my answer on How to specify AddressFilterMode.Any declaratively for how to create an extension to allow AddressFilterMode.Any
to be specified through configuration without requiring code attributes.
In the web.config
of the service host, the endpoint element must have an absolute URL in the address attribute that is the public URL that will be used by the client. In the same endpoint element, set the listenUri
attribute to the absolute URL on which the service host is listening.
The way I determine what the default absolute URI the host is listening on is to add a service reference in a client application which points the the physical server where the service is hosted. The web.config of the client will have an address for the service. I then copy that into the listenUri attribute in the hosts web.config.
In your service behavior configuration, add the element serviceMetaData
with attribute httpGetEnabled=true
So you'll have something like this:
<serviceBehaviors>
<behavior name="myBehavior">
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
<!-- ... -->
<services>
<service name="NamespaceQualifiedServiceClass" behavior="myBehavior" >
<endpoint listenUri="http://www.servicehost.com"
address="https://www.sslloadbalancer.com"
binding="someBinding"
contract="IMyServiceInterface" ... />
</service>
</services>
I am not sure if this works with message security or transport security. For this particular application, the credentials were passed as part of the DataContract so we had basicHttpBinding
> security
> mode=none
. Since the transport is secure (to the ssl load balancer) there were no security issues.
It is also possible in to leave the listenUri attribute blank, however it must be present.
Unfortunately, there is a bug in WCF where the the base address of imported schemas in the WSDL have the listenUri base address rather than the public base address (the one configured using the address attribute of the endpoint). To work around that issue, you need to create an IWsdlExportExtension implementation which brings the imported schemas into the WSDL document directly and removes the imports.
An example of this is provided in this article on Inline XSD in WSDL with WCF. Additionally you can have the example class inherit from BehaviorExtensionElement
and complete the two new methods with:
Public Overrides ReadOnly Property BehaviorType() As System.Type
Get
Return GetType(InlineXsdInWsdlBehavior)
End Get
End Property
Protected Overrides Function CreateBehavior() As Object
Return New InlineXsdInWsdlBehavior()
End Function
This will allow you to add an extension behavior in the .config file and add the behavior using configuration rather than having to create a service factory.
Under the system.servicemodel
configuration element add:
<behaviors>
<endpointBehaviors>
<behavior name="SSLLoadBalancerBehavior">
<flattenXsdImports/>
</behavior>
</endpointBehaviors>
</behaviors>
<extensions>
<behaviorExtensions>
<!--The full assembly name must be specified in the type attribute as of WCF 3.5sp1-->
<add name="flattenXsdImports" type="Org.ServiceModel.Description.FlattenXsdImportsEndpointBehavior, Org.ServiceModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</behaviorExtensions>
</extensions>
And then reference the new endpoint behavior in your endpoint configuration using the behaviorConfiguration attribute
<endpoint address="" binding="basicHttpBinding" contract="WCFWsdlFlatten.IService1" behaviorConfiguration="SSLLoadBalancerBehavior">