views:

67

answers:

6

When using SqlConnection, it's important to always close it when used - either by .Close() or placing the SqlConnection in a "using". Unfurtunately, people, including myself, tend to forgot that and this is where the garbage collectors rescues me for a while until i've forgot to close my connections too many times or the number of people using the application grows.

I'd like to know, if even possible, how to detect if the garbage collector disposed the SqlConnection because it figured that it wasn't in use anymore or if the SqlConnection was closed the correct way.

Another way could be inheriting SqlConnection and putting a timer on it's initializer and check how long it took for the connection to be closed when disposing the class. I don't really like timers but the idea just came up while writing this.

Maybe there's a third and even smarter way to all this... What would you recommend?

+2  A: 

One rule of thumb says, "If you have to think about the garbage collector, you're probably doing something wrong." (Of course, there are other thumbs...)

Seems to me that ensuring that connections are closed either explicitly or via using and finally blocks is the best route.

Obviously, you already understand these techniques... so maybe a once-through-the-code and a possible refactor is all you need.

ewall
A: 

If you forget to dispose, the object will be finalized. There is no way to control the time at which this happens, and there is also no way for you to know if an object is finalized. A seperate thread has to be created in order to finalized objects, so it slows your application down. That's why you want to dispose. In all classes in the framework that implement IDisposable, a call to GC.SuppressFinalize is made, so the object isn't finalized.

There is no way for you to controll this behaviour. If your object isn't used anymore, it will automatically be collected. All you can do to stop this, is call GC.SuppressFinalize, but I wouldn't recommend that, because if you then forgot, you'd be screwed for life.

You can create a wrapper class though (not a child class), that you use in your code that provides a few simple methods that always call Dispose. Otherwise, just check really well.

Jouke van der Maas
+4  A: 

Since SqlConnection is sealed, you won't be able to inherit from it. (And I don't think it is a good idea to do so -- If it was possible, you should probably add your code in Dispose(false), because that is what the finalizer calls).

It is better to detect these kind of problems by using a static code analysis tool, which has the power to detect all places in your code where you forget to dispose a connection. There is one built in in Visual Studio, or you can use FxCop.

To help you not to forget disposing the connection, it is a good idea to:

  • Keep all DB connection code in one layer / assembly / module, so it is not scattered through the projects.
  • Have utility methods to perform SQL commands and returning the results; so you don't create SQLConnection more places than you need to.
  • Remember to utilize the C# using construct.
driis
+1 the best way to approach this is to get at the root cause and Dispose the connections.
Tuzo
+1  A: 

If your application is using SQL Connection Pooling (the default) it will not matter since connections are re-used and don't get closed when you call .Close() or leave a using() {} block.

http://msdn.microsoft.com/en-us/library/8xx3tyca.aspx

To answer your question, I dont believe there is a event for GC collection, however it would not matter if there was, because you would never know if the GC chose to recycle your object on that collection pass (not all objects are cleaned because of the generational algorithm).

I would also avoid attempts to use timers and and "checks" as you will likely hold references to the object and prevent it from ever being disposed.

David
But it does matter since if the connections are not closed then they are not returned to the pool so they will not be reused immediately. This could exhaust your connection pool or consume valuable resources causing issues.
Tuzo
Agreed, but the point is the OP wants to know "when" a garbage collection occurs. My point was that the collection of sql connections wont occur with pooling. The only solution is to actually fix and ensure .Close() is being called, not rely on a GC collect event or timer check.
David
A: 

First, if you're even considering using the GC, you've got serious problems somewhere. I suggest that the best way to ensure your code calls Close is to unit test your code using techniques like mocking. If your unit test indicates that Close was called, your code is correct and you don't have to do anything unnecessarily dangerous like mucking around with the Garbage Collector.

Second, if you still insist on going the runtime checking route, the only thing you should even consider doing is hooking the StateChange event of SqlConnection. That'll fire if the ConnectionState changes from Open to Closed, for example.

Randolpho
A: 

I am not very familiar with the garbage collector and don't know if there is a direct way to get the information but my first idea is the following one.

Just create a weak reference to a dummy object. If you look at the weak reference later and the object is no longer alive you can probably assume the a garbage collection occurred.

(This answer only applies to detecting garbage collector runs. I completely ignored the reason for doing this - there are much better strategies to deal with resource leaks.)

Daniel Brückner
That's the whole point, you need to dispose to prevent finalization. If you just keep a weak ref and check to see if it happened, you're already too late. (Garbage Collection comes after finalization).
Jouke van der Maas
Yes of course. As stated in the last sentence I only wanted to answer "Detecting if the garbage collector was invoked". You should not write code that leaks resources in the first place. And this can be efficiently avoided by performing static analysis and runtime profiling.
Daniel Brückner