After a bit of frustration with the WCF host and client, I decided it would be easier to split the client and service host projects. I did this, relatively easily but now the problem was getting the host to start first and then the client…and having the host start when doing work on the WCF service itself and keeping the client reference updated. Well, simply put, it was going to be a big pain (having 2 VS 2010’s open isn’t bad…but starting up the host every time I wanted to test or make a change would have been). I’ve also been considering having a web host to host these services – and the thing with most hosting providers, they don’t allow Windows services nor console/windows applications (and I wasn’t going to pay $45+/mo to have a hosted virtual server) so my only route was having the service hosting in IIS. Since most providers that allow WCF are running Windows 2008 or 2008 R2, this meant IIS 7 or 7.5, which means it’s compatible with my development environments within Windows 7, thankfully.
So, the client is now in it’s own solution. The client in this case is only for testing – the real client will be in the app. The client is “easy” to create as long as VS 2010 can get a service reference – with the client and host in one solution, that was becoming a pain. With IIS hosting, that pain should go away.
The service solution had a dll that contained the real “service” (the service contract and an implementation of that contract) and a console host. I’ve added a new WCF Windows Service project as described in the blog post (http://blog.lyalin.com/2008/04/creating-quick-sample-iis-hosted-wcf.html). Although this blog describes VS 2008, it applies to VS 2010 without any changes. I tried to cheat and extend my service library dll service class (with changing the SVC code behind as well) but, alas, when I browsed to the service, it basically told me that the ServiceContract cannot be inherited. So, to avoid that fight, I copied my library code into the new IIS hosted service project and removed the old library – I didn’t see a use for the old library outside of various hosting methods or for debugging…ah, debugging – hard to debug an IIS service with console write’s so I decided to keep the old console host so that I could see what was going on in the service though console writes (yes, archaic, I know – but works). I added a normal reference to the new Library dll in the host console application – no other code needed to be changed.
Now my hosting/service solution looks like this:
To publish the service to IIS, be sure to follow the instructions in the mentioned blog as VS will host it by default if those aren’t followed. Then right click on the WCF project and click Publish. A dialog box similar to the following should appear. For my settings, I set the service URL to my local machine and the site/application to one of the similar examples shown (eg Default Web Site/MyApp). Since this is a WCF service, I set the “Mark as IIS Application” and left everything else default.
After a successful publish, VS appears to update the Web.config file so it may ask if you want to update the file to the most recent changes.
To make sure everything works as expected, right click on the service file [yes, service file, not the project], then go to View In Browser. The familiar “You have created a service.” should appear. If not, check the Web config of the service and make sure the following line is set. VS 2010 creates the web config file and, by default, sets this to true for you.
<serviceMetadata httpGetEnabled="true"/>
Now, if we start the project, we should see the console host, as normal, which, according to it’s app config file will be using port 8000 instead of the IIS default of port 80. So, in the client, this will need to be changed accordingly depending on whether we want the IIS version or the console hosted version. For proof the host still works:
And with the client making a call against the console host
Unfortunately no easy way to tell if the IIS hosted version is working as expected (other than the fact it is using the exact same code, just a different hosting method). The easy way to check communication is to change the app config of the client to point to port 80.
Run the client again and we get:
Hmm…EndpointNotFoundException – but why? Well, let’s look at the service again in IIS – viewing the service in the browser we get and address of http://localhost/ExpressRecipeWCFLibrary/UserService.svc. But if we look at the client app config file we have:
http://localhost/UserService
Ok, two problems – application name we set when we published is showing in the URL and so is the .svc. Setting the app config service location fixes the problem, but, debugging with the console hosting app now goes away until it’s changed back. (just for curiosity sake, I tried to publish without the application name and my VS crashed…so, probably not a good way to get around this issue). Haven’t tried yet, but defining an endpoint for each the console and IIS host may be an option (an option which would have to be repeated for n services – could easily get nasty)… A workaround is to set the console base address to be that of the IIS service address, just be sure to change the port number – seems to work for this case. This may need a more elegant solution soon, maybe modifying the port or endpoint based on if it’s in DEBUG or just a normal build…anyway, something else to think about.
Yeah, just like my friend told me who is a computer technician. In fixing a computer, they always do a trial and error approach to say what's wrong with the computer.
ReplyDeleteNetwork Monitor Software