It's a cold day in Scotland
It is not "Winter is coming" as they say in Game of Thrones, but IT IS HERE. Actually it is there, in Scotland and Elisa has sent some pictures from her yard.
Slaying the Beast Known As...
Over the past two weeks, at work, I have been beating on a problem. I am glad to report that it has been solved but it was not fun. There were days that I did nothing but Google and change my code but nothing would work and because what I was working on can be done so many different ways, there was not a single Google result that directly addressed my situation. Which is why I am posting this now. I hope that this will help someone else.
If you write code in Visual Studio, .net and you write services - read on. If you have no idea what this means, I suggest you read now because if you continue you might get a headache.
The beast that I am referring to is WCF. [Windows Communications Foundation]
Writing a WCF Service can be daunting if you have never written a Web Service before and trust me it can be daunting even if you have written an old style Web Service but have never touched WCF.
But configuring the Service and the client that uses it can make a seasoned developer curl up in a ball, under their desk, and whimper if not make them out right CRY.
This post won't go into how to write a WCF Service.
This post won't go into how to write a Client to consume the Service either.
What it will do is detail the problems it has taken over a week to sort out on the configuration of the service host and the client when using basicHttpBinding (again, if you don't know what that is I suggest you run, run fast and run NOW!). Yes there are other binding options but this is the one I was dealing with.
Here is the set up.
I have a WCF service. Right now it runs on a production machine using HTTP (that's an internet protocol for those of you who did not run away) We will be eventually using HTTPS with Certificates but for now, we want to use HTTPS with OUT cert's.
I need to test this on my local development machine. Yes, I have a cert installed in IIS. No, this post will not tell you how to create a cert or how to install one - that is what Google is for.
For calling your service over ONLY http this what should be in your config files. First up is the web.config which is for the Service Host and after that is the app.config which is for the client.
Note: all the other settings have been removed for brevity.
If you want to call your service over HTTPS with NO certificates, each file would look like the following. In the Web.confg you change the security mode to transport and then add the transport client credential type. Because we are not using certs, the type is NONE. And don't forget to change the address URL to have the ‘s’ in the HTTP as shown in the next two screen shots.
But wait, there is one more thing that must be verified and that is the SSL settings in IIS. Your certs should be installed at this point but NOT turned on.
But what if you have different clients and one will call over https and one will call over http AT ANY TIME. It would be great if you could have the configuration files set up so you could call either protocol.
The app.config can have two client enpoints and bindings and we will come back to that, but the web.config can only have one named service per actual service in the service host.
I made the mistake of thinking that having two endpoints and two bindings would be the way to set up the configuration, so I set up my web.config to look like this…
Trust me, this does not work. The issue is with the web.config and how it is read by the system.
Adding a second endpoint and a second binding for the end point so one points at the http address and the other points at the https end point results in all sorts of errors such as:
And the documentation is not that great on how accomplish this scenario. But this last error gave us a hint and that is the word “VIRTUAL”
Here is what the two configuration files should look like and afterwards I will explain why.
Why does this work? Originally we configured the address of our service explicitly in the address attribute of our service's endpoints. That works when calling only http or only https. When you want both, there is a conflict because the service really does not know what end point to serve up to the client. I know, it seems like it should because we have explicitly specified the URL to use in the client; it is the service that is getting confused. We have been using RELATIVE ADDRESSES.
If you look at the addresses specified in the client configurations, we have added what appears to be a subfolder to the addresses used in the client endpoints. These are not subfolders of the service. They are the NAMES of the service ENDPOINTS. And in the host node, we have two base addresses one for http and one for https. THIS USES VIRTUAL ADDRESSES! Because the client specifies which end point of the service to use, the Service uses what is called *Discovery mode* and it works out based upon the behaviors and bindings what security mode to use and thus it the url to use.
No, I will know go into the mechanics of what is really going on under the hood – even my eyes will roll into the back of my head if I did that.
I just hope that this will help someone else and save them the 3 days it took me to figure it out.
And a big thank you goes out to El Jeffie who also worked on this and found the final solution.
Laurie lives in central Texas with Erich, a.k.a. "the shop elf", her hubby of 35+ years and Cowboy Boots, the cat; her metals studio including 100+ hammers and 300+ chasing tools; her sewing studio which has a sewing machine, a closet filled with fabric, hundreds of skeins of embroidery floss and perle cotton, silk and other materials, and Mrs. King the dress dummy; two weaving looms, assorted knitting needles, tubs of yarn; lots of books; plus a plethora of geeky tech gadgets, computers, and more.