1

I am creating a LINQ to SQL DataContext by passing it an already open connection. This works, except I'm now leaking connections everywhere because although I dispose the DataContext when I'm finished, the connection never gets closed. I understand this is by design.

What I would like to do is ensure that my connection gets closed once my DataContext is disposed.

I have tried to override Dispose on the DataContext, like this:

protected override void Dispose(bool disposing)
{
    this.Connection.Close();
}

However, this does not work... I get an ObjectDisposedException. Setting a breakpoint shows me that everything is already disposed at this point!

The only workaround I have found, is to hide the Dispose method on DataContext. Like this:

    public new void Dispose()
    {
        this.Connection.Close();

        base.Dispose();
    }

However, this has a bit of a bad code smell to me. What is the recommended way to proceed here?

Complete code sample (DataClasses1DataContext is an empty DataContext):

class Program
{
    static void Main(string[] args)
    {
        string connectionString = "server=localhost;initial catalog=master;Integrated Security=SSPI;";

        for (int i = 0; i < 100; i++)
        {
            var connection = new SqlConnection(connectionString);
            connection.Open();

            var ctx = new DataClasses1DataContext(connection);
            ctx.ExecuteCommand("declare @i int");

            ctx.Dispose();
        }

        Console.ReadKey();
    }
}

public partial class DataClasses1DataContext
{
    protected override void Dispose(bool disposing)
    {
        // This will throw an ObjectDisposedException
        // this.Connection.Close();
    }

    public new void Dispose()
    {
        // This will work
        // this.Connection.Close();

        //base.Dispose();
    }
}
TheNextman
  • 12,428
  • 2
  • 36
  • 75

1 Answers1

2

The problem is Dispose() sets disposed before calling Dispose(bool). This causes the exception when you call Connection. There does not appear to be a way around this.

However I have to ask, why is this necessary? Dispose(bool) calls Dispose on the Provider which contains the Connection and should handle closing it automatically.

Guvante
  • 18,775
  • 1
  • 33
  • 64
  • Thank you. From looking at reflector, it seems the connection is only disposed under certain conditions (probably, if it was opened by Linq to SQL in the first place). – TheNextman Feb 16 '12 at 17:24
  • And superficially, at least, it appears that Linq to SQL does not have a public provider model that I can just change. Seems that my workaround is the only way. – TheNextman Feb 16 '12 at 17:27
  • @TheNextman: Are you using the `SqlProvider`? It appears that it should always close the connection. Unless I am missing somewhere where `conManager` is getting set to `null` (it is constructed outside a branch). – Guvante Feb 16 '12 at 17:48
  • It's not clear to me after reading the code in Reflector. However, the documentation (and backed up by running my sample code while using SQLServer:General Statistics:User Connections performance counter) demonstrates that, if you either give Linq to SQL an already open connection, or open it's connection object yourself, it will *not* dispose/close it in destruction – TheNextman Feb 16 '12 at 18:10
  • @TheNextman: Interesting, it is too bad there is no easy way to get to the connection object during `Dispose()`. Or for that matter a way to explicitly request control like how `Stream` is handled. – Guvante Feb 16 '12 at 18:16
  • 2
    After some more investigation: L2S will dispose the connection if you construct the DataContext using a connection string. If you construct with a connection, it will not dispose it. Makes sense :) – TheNextman Feb 17 '12 at 18:39