A constant niggle in the arena of computing is the way in which nobody takes responsibility. If your computer crashes whilst you’re, say, playing an online game, and you call the manufacturer, they’ll explain it’s probably a software problem, perhaps a driver you, the user, stupidly installed. If you call the driver vendor, they’ll explain that it’s probably some other driver you, the user, stupidly installed; or perhaps some other hardware (not theirs, of course) is causing you problems; or perhaps your game has a bug in it. If you call the game publisher, they’ll explain that it’s clearly a hardware problem, or you need to upgrade your drivers. Nobody will hold their hand up and say, “Sorry, my bad, we screwed up. Our product is inferior, and we will rectify that for you, right now.”
On a microscopic level, the same situation occurs when a contract breaks down between the caller and callee of an interface. The case which I wish to briefly whine about is that of web services.
I’m working on a .NET 2.0 desktop application which uses a third party web service. Now it generally works nicely. Much to my surprise, however, I periodically notice the application cough, gasp for air, and finally collapse spreadeagled on the floor. By the time I can attend it, I observe that it has written me a final message with one trembling finger, using its own vital fluids as ink:
System.Net.WebException : The underlying connection was closed: A connection that was expected to be kept alive was closed by the server.
How nice of it.
Googling around revealed a few more facts. It appears that .NET and the web service implementation are having a disagreement over the lifetime of the HTTP connection which they’re using to talk. .NET asked for the connection to be kept up, if you don’t mind, so that it can avoid the overhead of reopening it all the time. The remote server agreed, but at some stage this became impossible. This may be because the remote server is a lying son of a VAX; or because there are inconvenient firewalls between my client and the server, interfering with the keepalive; or because the server encountered a minor problem which .NET didn’t understand, and this issue got blown out of proportion until it finally manifested as a dropped connection. Opinion on the internet seems divided; all of these are cited as plausible reasons. Meantime, .NET, for its part, doesn’t like the internet failing to work flawlessly. In its idealistic view, this simply should not happen! What is the world coming to? And, it reasons, if this is occurring, surely someone should be alerted so they can a) fix the internet; and/or b) rewrite the server code? Overall, the best thing to do from .NET’s point of view is not to, say, reopening the offending connection and try again; no no, the best plan is to throw an exception.
Now the thing that vexes me is not that .NET likes throwing exceptions whenever anything even vaguely unconventional occurs; such as, for example, if I were to come to work wearing a hat. I’ve grown accustomed to its idiosyncracies in this regard. What vexes me is that .NET has deliberately set itself up to work under a theoretical and idealistic optimal case (where keepalive connections are always kept alive), and then complains bitterly when its lofty ideal is not upheld by the cruel world.
In any case, there is a solution to this problem. One simply has to find the web service’s generated code within the client application, which derives from WebClientProtocol or one of its subclasses. One then overrides the GetWebRequest method as follows, to tell .NET not to bother trying to keep connections alive:
protected override System.Net.WebRequest GetWebRequest(Uri uri)
WebRequest request = base.GetWebRequest(uri);
(request as HttpWebRequest).KeepAlive = false;
Simple stuff. But there are a few little niggles; the .cs file in which one is supposed to override this method is generated code. So, if the web service’s documented interface changes (which has been known to occur rather regularly on the internet), the code needs to be regenerated. Now I personally object to trawling through generated code each time I regenerate it, adding in hacks here and there. It’s just wrong.
So, a slightly more tasteful solution was required. Instead, I derive a class from the generated code for the web service, called eg. SafeWebService. Inside this class, I override the GetWebRequest method. I then be sure to make use of SafeWebService rather than the original generated code. This way, I can regenerate the code and not have to make any changes, since my modifications are not contained therein.