Daniel Fisher (lennybacon.com)

SOA, DATA & THE WEB

WCF Data Services Client does not close connections!

Have you ever worked with the WCF DataServices Client? I was contributing to the nuget project and experienced *some* problems. After a few operations (web request through either the WCF Data Service Context or manually through a WebRequest) operations started to time out. I used (the fabulous) reflector pro to digg into the sources. What you see here is a class utilized to return the result of a WCF Data Services request.  

namespace System.Data.Services.Client { using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Runtime; using System.Threading; internal class QueryResult : BaseAsyncResult { internal void Execute() { try { HttpWebResponse response = null; try { response = (HttpWebResponse) this.Request.GetResponse(); } catch (WebException exception) { response = (HttpWebResponse) exception.Response; if (response == null) { throw; } } this.SetHttpWebResponse(Util.NullCheck<HttpWebResponse>(response, InternalError.InvalidGetResponse)); if (HttpStatusCode.NoContent != this.StatusCode) { using (Stream stream = this.httpWebResponse.GetResponseStream()) { if (stream != null) { Stream asyncResponseStreamCopy = this.GetAsyncResponseStreamCopy(); this.responseStream = asyncResponseStreamCopy; byte[] asyncResponseStreamCopyBuffer = this.GetAsyncResponseStreamCopyBuffer(); long num = WebUtil.CopyStream(stream, asyncResponseStreamCopy, ref asyncResponseStreamCopyBuffer); if (this.responseStreamOwner) { if (0L == num) { this.responseStream = null; } else if (asyncResponseStreamCopy.Position < asyncResponseStreamCopy.Length) { ((MemoryStream) asyncResponseStreamCopy).SetLength(asyncResponseStreamCopy.Position); } } this.PutAsyncResponseStreamCopyBuffer(asyncResponseStreamCopyBuffer); } } } } catch (Exception exception2) { base.HandleFailure(exception2); throw; } finally { base.SetCompleted(); this.CompletedRequest(); } if (base.Failure != null) { throw base.Failure; } }

Have you seen it? The HttpWebResponse instance is never closed neither disposed. Let’s digg into the HttpWebResponse close method…

public override void Close() { if (Logging.On) { Logging.Enter(Logging.Web, this, "Close", ""); } if (!this.m_disposed) { this.m_disposed = true; Stream connectStream = this.m_ConnectStream; ICloseEx ex = connectStream as ICloseEx; if (ex != null) { ex.CloseEx(CloseExState.Normal); } else if (connectStream != null) { connectStream.Close(); } } if (Logging.On) { Logging.Exit(Logging.Web, this, "Close", ""); } }

The close method closes the network stream that is in the end associated with an tcp connection. A cite from the msdn documentation:

The response must be closed to avoid running out of system resources. The response stream can be closed by calling Stream.Close or Close.

This can be validated though a netmon trace:

image

The request I did manually (and closed properly) don’t keep a connection alive. The WCF Data Services Client calls do. This results in additional calls timing out.

Sad but true…

Comments

Should'nt the using statement take care of cleaning up? When you call this.httpWebResponse.GetResponseStream() you simply get a reference to m_ConnectStream and the using statement should call the Dispose which calls Close. The only thing that would not happen would be the possible call to ex.CloseEx(CloseExState.Normal); Is there something else which could be causing the calls to time out?

Write a comment