Running with Code Like with scissors, only more dangerous


WCF for Fun and Profit

Posted by Rob

I've alluded in the past that I got my start in computers because of games; I also ended up getting started in programming because of games.  I happen to be a big fan of the WarCraft and StarCraft series produced by Blizzard Entertainment, and it was my association with (and desire to make a good website for!) a group of people on their gaming service called that got me involved with programming, and that's where the "Fun" part of this comes from.  I'm not sure where "Profit" comes into play.

With the knowledge that StarCraft 2 is on the horizon, and the new announcement of Diablo 3, I've been working on a series of open-source projects collectively named after my cat Jinx (we had the name WAY before the movie), which includes a third-party utility library that manages client connections to's chat service, a full-blown client, and some plugins for the client.  When I first got into the bot-making community I found a project called WebChannel and WebBot -- these projects allowed clients to broadcast their channel information via another service called BotNet, which then rendered the content over an ISAPI Extension.  At the time I only really knew the basics of C#, and I could not find a way to mimic the functionality (WebChannel streamed content over the wire by removing Content-Length from HTTP headers, and then never closing the client connections).  To my knowledge, there is not a way to get ASP.NET to not send the Content-Length header; I guess I've never pursued it after about three years ago.

When starting this project, I knew from the start that I wanted to recreate the functionality (particularly because WebChannel has been unavailable for a long time).  But I also knew that I wanted to do it without recreating a lot of functionality; in the past, submitting complex types to Web Services caused the complex types to be generated as proxies as part of the client assembly, and there was no support for inheritance/polymorphism.  I knew that all of my event arguments would derive from a single class, and so polymorphism seemed to be the way to go.  Plus, all complex types serialized to and from XML needed to have a default public constructor and public gettable/settable properties, which in my mind would severely break encapsulation.  The question was, how to go about pushing my client content to a web site.

It turns out that WCF Data Contracts were the answer to my problem.  By decorating all of my classes with [DataContract] and [DataMember] I was (mostly) able to easily serialize the classes over the wire, and the best part was that I only needed one method, and inheritance was observed!  I didn't even have to break encapsulation; consider the ChatMessageEventArgs class.  By applying [DataMember] to fields instead of properties, I didn't need to make my properties settable, which means that the objects should be (more or less) immutable to code consumers.  By sharing the common code between the web server and the client plugin, I was (mostly) able to avoid any kind of object recreation, and even more fun, the types were rendered to JavaScript automatically as part of ASP.NET AJAX.

The astute reader might have noticed a lot of qualifying "mostly" asides in that last paragraph.  I'll get to that.

The final result - well, not really final - was a very Meebo-esque client that shows a live display of the channel Diablo II USA-1 on the US-East server.  (If it's not up I apologize).  (Also, I definitely take no credit for what is said in the channel; I'm just showing that it can be done).


There have been some trials on this project.

  • Proxy generation ignored shared types -- this occurred once I started sending some certain complex types over the wire.  When I added the service reference and looked at the Object Browser in Visual Studio, I would see all of my BNSharp.dll-driven classes being recreated.  This was what I wanted to avoid!  It turned out to be that I was not decorating some enumerations with [EnumMember] - once I did this, proxy generation returned to normal.
  • I received an error that "more than one http binding cannot be configured" when attempting to view a WCF service.  Because I use a shared web host, and multiple hosts were configured on the same IP, I was getting an error when setting up WCF services on my host.  It turned out that this was corrected with a web.config setting in .NET 3.5 called <baseAddressPrefixFilters>.
  • I then received an error that my plugin was no longer authorized once I moved it into the shared hosting environment.  I eventually tracked this down to using wsHttpBinding (the more secure Web Services HTTP binding), and had to change to basicHttpBinding.
  • I then received an error that my application was sending content-type "application/soap+xml, charset='utf-8'", which was not the expected "text/xml, charset='utf-8'".  Ultimately this ended up being traced to not using basicHttpBinding on the client as well.  That one had to be the most frustrating; honestly, it's the same thing.

What needs to yet be done

I've noticed that the client tends to cache the content returned from the server.  I need to access the HttpResponse and set its cacheability.

Other than that, it's just the user interface that needs to be done.  We've got the basics, but it needs a channel list and the ability for users to type a password into the client to communicate with the host application and then interact with the channel.

Tagged as: , No Comments