SSL for webHttpBindingServices Thursday, August 26 2010
It's easy to forget how slippery a slope a proper WCF configuration is, especially when you are deploying services to multiple environments. While you local development and QA environments do not have an SSL requirement, your UAT and production environments do.
Service calls that may have passed with flying colors is dev. and QA are now failing left and right with 500 errors abound. If this sounds like a familiar situation hopefully this post clears your worries.
Let's use the following service declaration for this example:
<services> <service behaviorConfiguration="TaciturnDiscourse.Services.ClientServicesBehavior" name="TaciturnDiscourse.Services.ClientServices"> <endpoint address="" binding="webHttpBinding" contract="TaciturnDiscourse.Services.IClientServices" behaviorConfiguration="TaciturnDiscourse.Services.ClientServicesEndpointBehavior"> <identity> <dns value="localhost" /> </identity> </endpoint> <endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" /> </service> </services> <behaviors> <endpointBehaviors> <behavior name="TaciturnDiscourse.Services.ClientServicesEndpointBehavior"> <enableWebScript /> ;</behavior> </endpointBehaviors> <serviceBehaviors> <behavior name="TaciturnDiscourse.Services.ClientServicesBehavior"> <serviceMetadata httpGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="false" /> </behavior> </serviceBehaviors> </behaviors>
But what if you were to deploy this out to an environment which requires SSL?
Does this look familiar?
Exception message: Could not find a base address that matches scheme http for the endpoint with binding WebHttpBinding. Registered base address schemes are [https].
The reason you are seeing this error is because you have no explicitly stated that the service needs to allows any kind of security. Remember, WCF is opt-in, not opt-out.
So, let's add some binding configuration around our service to make it like our encrypted environment.
First to our endpoint, let's add a new bindingConfiguration like such:
<endpoint address="" binding="webHttpBinding" contract="TaciturnDiscourse.Services.IClientServices" bindingConfiguration="TaciturnDiscourse.Services.ClientServicesEndpointBinding" behaviorConfiguration="TaciturnDiscourse.Services.ClientServicesEndpointBehavior">
Then let's add the actual configuration - where we specify the security mode to transport.
<webHttpBinding> <binding name="TaciturnDiscourse.Services.ClientServicesEndpointBinding"> <security mode="Transport"> </security> </binding> </webHttpBinding>
Perfect! Deploy that and........
CRAP! Not quite there yet... ahhh... Mex...
Exception message: Could not find a base address that matches scheme http for the endpoint with binding MetadataExchangeHttpBinding. Registered base address schemes are [https].
Here you have two options.
- Drop the mex binding. It's there so that other applications can consume your service by getting the metadata around your service. However - if you have no other apps that will be consuming the service from here, dropping this endpoint is ok.
Update your mex binding like so:
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />
Some of you win - others of you fail.
Exception message: The HttpGetEnabled property of ServiceMetadataBehavior is set to true and the HttpGetUrl property is a relative address, but there is no http base address. Either supply an http base address or set HttpGetUrl to an absolute address.
And this isn't your fault. If you are using this service via jQuery or some other JSON type transfer style - you probably have one more configuration for your service behavior which looks like this (I also included it in the example):
<serviceMetadata httpGetEnabled="true" />
Oh WCF, and your explicit nature. This fix is easy - because we're using https... not http.
<serviceMetadata httpsGetEnabled="true" />
This should fix all of your WCF webHttpBinding service issues when running with SSL, but if it doesn't don't hesitate leave a comment or shoot me an email.