[CSHARP-154] MongoConnection.Close() and Dispose Created: 20/Jan/11  Updated: 02/Apr/15  Resolved: 15/Mar/11

Status: Closed
Project: C# Driver
Component/s: None
Affects Version/s: 1.0
Fix Version/s: 1.0

Type: Improvement Priority: Minor - P4
Reporter: Aristarkh Zagorodnikov Assignee: Robert Stam
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

MongoConnection.tcpClient might be not connected in MongoConnection.Close() leading to a handled InvalidOperationException (I encountered this when simulating reading from a replica set, shutting down primary member in the process). While this does not affect functionality, debugging (especially online) and performance suffers from extra exceptions.
Looks like TcpClient.GetNetworkStream() throws an exception instead of returning null if it's not connected, so checking TcpClient.Connected before trying to get the stream (actually around entire first try/catch block in MongoConnection.Close()) would be nice to prevent that extra exception.

I also don't think that casting the TcpClient to IDisposable and calling Dispose(), along with closing the stream explicitly is necessary, because TcpClient.Close() calls Dispose() internally.
I've seen the following: "// note: TcpClient.Close doesn't close the NetworkStream!?" – this does not seem to be the case.

The following is partial output from Red Gate Reflector utility on certainl BCL methods from .NET 4:

public void TcpClient.Close()
{
if (Logging.On)

{ Logging.Enter(Logging.Sockets, this, "Close", ""); }

((IDisposable) this).Dispose();
if (Logging.On)

{ Logging.Exit(Logging.Sockets, this, "Close", ""); }

}

void TcpClient.IDisposable.Dispose()
{
this.Dispose(true);
}

protected virtual void TcpClient.Dispose(bool disposing)
{
if (Logging.On)

{ Logging.Enter(Logging.Sockets, this, "Dispose", ""); }

if (this.m_CleanedUp)
{
if (Logging.On)

{ Logging.Exit(Logging.Sockets, this, "Dispose", ""); }
}
else
{
if (disposing)
{
IDisposable dataStream = this.m_DataStream;
if (dataStream != null)
{ dataStream.Dispose(); }
else
{
Socket client = this.Client;
if (client != null)
{
try
{ client.InternalShutdown(SocketShutdown.Both); }
finally
{ client.Close(); this.Client = null; }
}
}
GC.SuppressFinalize(this);
}
this.m_CleanedUp = true;
if (Logging.On)
{ Logging.Exit(Logging.Sockets, this, "Dispose", ""); }

}
}

public void Stream.Dispose()
{
this.Close();
}

public virtual void Stream.Close()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}

Neither Stream.Close() nor Stream.Dispose() are overriden in NetworkStream (only Dispose(bool) does, but it doesn't matter).

This is also related to http://jira.mongodb.org/browse/CSHARP-150



 Comments   
Comment by Robert Stam [ 15/Mar/11 ]

Simplified implementation of MongoConnection.Close based on the information provided. Thanks for the detailed information!

Generated at Wed Feb 07 21:35:57 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.