How to Resolve "Unable to read data from the transport connection" Error

Previously when dealing with Web Service calls, I've discussed on how to resolve the TargetInvocation Errror.

This time, I've encountered another error in the mischievous world of Web Service, caused by Interop, which was caused by either Vista/Windows 2008 programmers not happy with Apache/PHP programmers or Apache/PHP programmers just too lazy to keep up with API changes in Microsoft's latest OS.

It happens while I was happily using my WinForms app to upload some data via PHP's web service...

ScreenShot059

Did you notice something weird with the above screenshot? Yeah, how can an 80KB file finished uploading while a 17KB file takes so long too upload? Tell yourself to prepare for some exceptions...

Then the inevitable happened... Exception Thrown with Message "The underlying connection was closed: An unexpected error occurred on a receive." It has an Inner Message of "Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host."

Now, if you Google around, you may arrive at this website or similar suggestion: Disable HTTP Keep-Alive.

But that's not what's causing this problem, as I soon see this thing popping up:

ScreenShot056

ScreenShot057

You see, the reason the Exception was thrown was because after accepting One Successful Upload, the server somehow crashes and quickly restarts and reloads all sessions, so it appears as though nothing crucial happened. But the problem is that the Second Upload (17KB) is still using the old connection before the Server Restart, and now that connection is kaput (or Remote Guys & WCF will love to say the channel is at fault). At fault means you can no longer send data through that connection, so you have to open a new connection to the server.

We could catch the exception and just re-invoke the call, but don't you think it's a performance issue when you leave all those faulted channels open?

So in my case I want to close the fault channel and return error code to the caller, so that my WinForms app can display Error Red Bar and put it back at the end of the queue.

Here's how you do it:

1. Open up Reference.cs (the generated Proxy class wsdl.exe or Add Web Reference generated) and override the GetWebRequest method:

protected override WebRequest GetWebRequest(Uri uri)
{
    WebRequest request = base.GetWebRequest(uri);
    request.ConnectionGroupName = "Z-Channel";
    return request;
}

2. Open up your Uploading codefile, and do the following

public IResponse UploadDocument(IUploadFile upload)
{
    try
    {
        // Code to Upload Files
        ...
    }
    catch (Exception ex)
    {
        if (ex.InnerException != null &&
            ex.InnerException.Message
            .Contains("Unable to read data from the transport connection"))
        {
            ServicePoint sp = ServicePointManager.FindServicePoint(new Uri(_url));
            sp.CloseConnectionGroup("Z-Channel");
            return Config.IResponseFactory(false, "Channel Faulted");
        }

        return Config.IResponseFactory(false, ex.ToString());
    }

    return Config.IResponseFactory(true, string.Empty);
}

And I get the behaviour I expected below:

ScreenShot060

Now instead of panicking "Exception...exception!" , my WinForms will record the upload as error, and I can automatically re-queue it for upload... or leave it to the users manually.

There, I hope that will help some folks dealing with Web Service Connection Fault... remember if you decide to re-invoke Web Service Call without closing current connection, the poor server in the other end will eventually have too many connections open and start to degrade in performance. Or it could be the other way around, the client will have too many connections open to a non-existent server.

Share this post: | | | |
Published Thursday, October 09, 2008 10:03 AM by zeddy

Comments

No Comments
Powered by Community Server (Commercial Edition), by Telligent Systems