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:
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…