- December 9th, 2012
- Write comment
I was recently required to write a small WCF service to run over https. Simple enough. I configured a simple basicHttpBinding with transport security and all was well. The service was run through the usual set of test and acceptance environments and was given the green light to go to production. On deployment day we ran into a somewhat unexpected problem. The service was throwing an error along the lines of …
“Could not find a base address that matches scheme https for the endpoint with binding basicHttpBinding. Registered base address schemes are [http]:”
This error occurs when the IIS server doesn’t have a binding to the scheme you have specified … in our case https (if you get this on a dev machine you need to read up on creating a self signed certificate so you can test https locally). As it turns out our live servers do not have an https binding in IIS. All of the https traffic and certificates are handled by load balancers and the traffic is forwarded as http from that point. Ok then … so we can just set up WCF without transport security and it should be fine right? No … you need the wsdl to contain the address to the load balancer … ie the urls should start with https, but since the service is running without transport security it generates the wsdl with http urls.
One simple solution would be to create an https binding on each of our servers and let the service run with transport security. Our systems guys weren’t keen to say the least. I’m not a systems guy but there are a number of servers that need to be configured and, just as it makes sense in software, it makes sense to centralise the certificates etc. So that wasn’t an option.
I did a *lot* of searching over the web for articles that might resolve this issue. There is another problem related to this to do with message security but in my case I was only using transport security so they didn’t apply. It would seem that problem is much more common than mine as I couldn’t find much at all about it. I eventually stumbled across the ‘externalMetadataLocation’ attribute that can be added to the mex endpoint and had an idea. I could simply download and edit the wsdl to contain load balancer urls then use this attribute to tell the service to publish the edited wsdl.
It turned out to be *almost* as simple as that … I also had to download the auto generated xsd files and edit them also. So here’s what to do …
1) Configure your service to run on basicHttpBinding with no transport security
2) Browse to the wsdl in the browser on your dev machine and copy it to a text editor.
3) Look in the wsdl file for the urls that end in xsd=xsd0 and browse to these in the browser and copy them to the text editor.
4) *Carefully* edit all urls in the files to point to the load balancer urls.
5) Don’t forget to edit the xsd file urls in the wsdl to where they will be hosted in production.
6) Deploy these files to a server.
7) Configure your mex endpoint with the externalMetadataLocation attribute (in your dev and test environments just leave this attribute out and use the automatic generation)
<behavior name=""> <serviceMetadata httpGetEnabled="True" externalMetadataLocation="https://MyServiceUrl/Wsdl/theWsdl.wsdl"/> </behavior>
Your service will be available on the http schema but will respond to mex requests with the wsdl file containing the https urls to the load balancer. When a request is made the load balancer will decrypt the request then forward it to the service on http. The response will return to the load balancer over http which it will then encrypt and send over https … all is well.
The downside to this approach is, of course, that when new methods are added to the service or changes are made to the signatures of existing methods the wsdl and xsd files must be maintained manually by repeating the process used to create them. Whilst this isn’t too horrible it might catch new developers on the system by surprise so its worth sticking a giant README file in there.