Is EntLib 5 leaking connections?

Topics: Data Access Application Block
Dec 28, 2010 at 12:58 PM

I've recently migrated some web apps which were using entlib 4.1 to entlib 5.
By using the ExecuteReader method I'm now closing the inner as well as the outer DataReader, but it seems something does not works as expected, and I'm seeing that connections are not properly closed causing exceptions when the maximum pool size is reached.

For now I just rolled back everything and the connection pool started working again as expected.

Am I the only one seeing this?

 

Dec 29, 2010 at 1:05 AM

Could you post the relevant code?

 

Sarah Urmeneta
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com

Dec 29, 2010 at 8:45 AM

Here is a quick piece of code that in my mvc application is leaking connections. Please notice that a new connection is opened in 90% of requests, in the remaining 10% of cases it correctly recycle one from the pool. This does not happen with EntLib 4.1...

    public sealed partial class Repository
    {
        private SqlDatabase _db;

       public Repository()
       {
              _db = new SqlDatabase(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);
       }

        public List<string> ListValues(int id)
        {
            List<string> entitities = new List<string>();

            using (RefCountingDataReader wrapper = (RefCountingDataReader)_db.ExecuteReader("mysp", id))
            {
                using (IDataReader dr = wrapper.InnerReader)
                {
                    while (dr.Read())
                    {
                        entitities.Add((string)dr["column1"]);
                    }
                }
            }

            return entitities;
        }
    }

Dec 30, 2010 at 8:00 AM

Hi,

Quoting Chris Tavares from one related post (http://entlib.codeplex.com/Thread/View.aspx?ThreadId=211288) - "be sure to close the original, outer datareader, not the inner one. Otherwise you'll screw up the connection management.". Looking at the source code, what happen is that once the innerReader is the first one that has been disposed there is no way the RefCountingDataReader connectionWrapper will be disposed causing the leak. With this what I can suggest is to have something like the code below instead; 

        public List<string> ListValues(int id)
        {
            List<string> entitities = new List<string>();

            using (RefCountingDataReader wrapper = (RefCountingDataReader)_db.ExecuteReader("GetOneProduct", id))
            {
                while (wrapper.InnerReader.Read())
                {
                    entitities.Add((string)wrapper.InnerReader["ProductName"]);
                }
            }      
               
            return entitities;
        }

Obviously this doesn't happen in 4.1 because RefCountingDataReader is not yet available in that version. Hope this helps.

Gino Terrado
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com

Dec 30, 2010 at 12:43 PM
Edited Dec 30, 2010 at 6:45 PM

Gino, thank you very much, I missed that post.

Anyway if I understood it correctly I should be able simplify it a bit by using the IDataReader interface instead of the SqlDataReader class:

        public List<string> ListValues(int id)
        {
            List<string> entitities = new List<string>();

            using (IDataReader dr = _db.ExecuteReader("GetOneProduct", id))
            {
                while (dr.Read())
                {
                    entitities.Add((string)dr["ProductName"]);
                }
            }      
               
            return entitities;
        }

Am I right? I tested it and seems to work as expected!

Dec 30, 2010 at 3:43 PM

Yes you are correct, using the IDataReader should work. I was specfically speaking for RefCountingDataReader on my last post. Anyway, I'm glad you're able to get through on this one :o)

Gino Terrado
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com