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
SqlTransactionobject 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
usingblock, or thetry/catch/finallyblock, 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
IDisposableyourself just to wrap around another manage object'sDisposemethod, 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 ausingblock, 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.