I have an ASP.NET Web API that uses an SqlConnection
to connect to a database. I have a data access layer class which has an instance variable containing the connection. I do this for a couple of reasons:
- the calling code can override the connection string in the constructor of the DAL class (e.g. for test code)
- there are some cases where the API controller needs to open an SQL connection, begin a transaction, then call several methods in the DAL class before committing (or maybe rolling back) the transaction. So, closing and re-opening the connection per method will not work because I have to hold the connection open (and even keep the
SqlTransaction
object in scope - I'd do that by making it also an instance variable) in order to not have the transaction rolled back between DAL calls. - It also simplifies code readability, so you're not duplicating code all over the place to open SQL connections.
When I stress-tested my API, by feeding it hundreds of requests per second, I hit up against the SQL connection pool exhaustion issue. Further investigating shows that this appears to be because the SQL connection is not being disposed of.
I do understand the IDisposable
pattern, but I am not sure how I would use it in this scenario. Here's my problem:
- Using the
using
block, or thetry/catch/finally
block, both require the object to be created, used and finalized within a single method. In the example above of a transaction that may need to persist across multiple method calls, this is not possible. - Microsoft (and other posts on SO) has recommended against simply putting a call to
Dispose()
in an object destructor, instead suggesting you do either of the options I specified in problem 1. - Microsoft also says you shouldn't implement
IDisposable
yourself just to wrap around another manage object'sDispose
method, but instead you should "simply call Dispose() on the object when you're finished with it." How would I do this in this scenario when I am not sure from within the DAL when the controller is finished using the SQL connection? (Also, this would mean I have to refactor the controller to wrap each call to the DAL in ausing
block, so it's just kicking the can down the road.)
The ideal solution for me would be to be able to somehow arrange to have the Dispose
method called on the SqlConnection
object when the controller has finished processing and is returning its response to the server for delivery to the frontend. To do this "by hand" I would have to violate point 3 above and create my own Dispose
method on my DAL that simply in turn calls the SqlConnection's Dispose
. Also it would mean I have to refactor many methods in all controllers to wrap all DAL access in using
blocks. It appears that ASP.NET will not automatically call Dispose
when the controller returns, which is why the connections are leaking.
In either case, it also makes for more verbose code. For example:
// we only need one method call from the DAL, so let's be compact
string someData = new DAL().GetSomeData(someParam);
now has to be written out as:
// we have to initialize here to keep the variable from falling out of scope after the using blocks
// we also must provide some value because the using block implies try/catch.
string someData = "";
using (DAL d = new DAL()) {
someData = d.getSomeData(someParam);
}
What would be the recommended way to implement this?
On a more generic plane, how do you actually deal with a disposable object that must persist between method calls (e.g. as an instance variable)? The need to use disposables within constructs like try/catch/finally
or using
seems to limit their use only to situations where the object can be created and disposed within a single method.