I was onsite today with a customer who was having problems getting WCF to work, and after much wailing and gnashing we finally arrived at a solution so I thought I would blog it. We were getting an EndpointNotFoundException with the error message “There was no channel that could accept the message with action …”. Then we’d get a warning saying “The incoming message is not part of an existing security session”. We went down a load of blind alleys on this before we finally got a solution (thanks go to Zulfiqar for helping a load).
The customer had a couple of servers hosted behind a load balancer. The load balancer was doing the heavy lifting of dealing with the incoming SSL request, and passing this on to the WCF service over HTTP. It took a while for us to get to the right configuration so here it is.
On the server side I defined the service etc. as follows…
<wsHttpBinding> <binding name="myBinding"> <security mode="None"/> </binding> </wsHttpBinding>
<behavior name="myBehavior"> <serviceMetadata httpGetEnabled="True"/> <serviceDebug includeExceptionDetailInFaults="False" /> <applyAddressFilterModeBehavior/> <!-- Discussed later on --> </behavior>
<service behaviorConfiguration="myBehavior" name="TestService.MyService"> <endpoint binding="wsHttpBinding" bindingConfiguration="myBinding" contract="TestService.IMyService"/> </service>
And the client was defined as follows…
<wsHttpBinding> <binding name="myBinding" > <security mode="Transport"> <transport clientCredentialType="None" /> <message establishSecurityContext="false" /> </security> </binding> </wsHttpBinding>
<endpoint address=https://MyServer/MyService.svc binding="wsHttpBinding" bindingConfiguration="myBinding" contract="TestService.IMyService" name="WSHttpBinding_IMyService" />
The one other thing we needed to do was to add the [ServiceBehavior(AddressFilterMode = AddressFilterMode.Any)] attribute to the service, as this effectively allows us to call to https://myserver/service.svc and have this processed by http://myserver/service.svc. The one hitch in our case was that there were a number of services that would need this same code change, and my customer didn’t want to have to change all of them.
So, I cranked out some code to setup the address filter mode using a custom behavior. The code for that one is below…
public class ApplyAddressFilterModeBehavior : IServiceBehavior { public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) { } public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { for (int i = 0; i < serviceHostBase.ChannelDispatchers.Count; i++) { ChannelDispatcher dispatcher = serviceHostBase.ChannelDispatchers[i] as ChannelDispatcher; if (null != dispatcher) { foreach (EndpointDispatcher endpoint in dispatcher.Endpoints) { endpoint.AddressFilter = new MatchAllMessageFilter(); } } } } public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { } }
The behavior is applied to the service by using another class which I defined within the same assembly…
public class ApplyAddressFilterModeBehaviorElement : BehaviorExtensionElement { public override Type BehaviorType { get { return typeof(ApplyAddressFilterModeBehavior); } } protected override object CreateBehavior() { return new ApplyAddressFilterModeBehavior(); } }
The behavior is added to the service in the config file by adding in a couple of elements…
<system.serviceModel> <extensions> <behaviorExtensions> <add name="applyAddressFilterModeBehavior" type="Test.Behaviors.ApplyAddressFilterModeBehaviorElement, Test.Behaviors, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/> </behaviorExtensions> </extensions>
With that defined all I then need to do is update the service behavior to add a reference to the above extension…
<behaviors> <serviceBehaviors> <behavior name="myBehavior"> <serviceMetadata httpGetEnabled="True"/> <serviceDebug includeExceptionDetailInFaults="False" /> <applyAddressFilterModeBehavior/> </behavior> </serviceBehaviors> </behaviors>