"Access to disposed closure" in LINQ

Hi,

Why am I getting "Access to disposed closure" for this block of code:

 

var query = from u in db.User
            from c in db.Contact.Where(p => u.UserId == p.ContactUserId && p.ContactMain).DefaultIfEmpty()
            select new BO.UserInfo { User = u, Contact = c };


or this one:

 
var query = from p in db.Product
            orderby p.ProductName
            select new BO.ProductList
            {
             Id = p.ProductId,
             Name = p.ProductName,
             Selected = (from pc in db.ProductCategory where pc.ProductCategoryCategoryId == categoryId && pc.ProductCategoryProductId == p.ProductId select pc).Any()
            };


I underlined + red where it's complaining. Any ideas? Thanks.
12 comments
Comment actions Permalink

It's hard to say without seeing all the code, but I would guess that you have your 'db' variable wrapped in a using statement.  Keeping in mind that execution of linq queries are deffered until they are actually enumerated, something like this:

using(var db = ....)

{

 var query = from u in db.User

 from c in db.Contact.Where(p => u.UserId == p.ContactUserId && p.ContactMain).DefaultIfEmpty()

 select new BO.UserInfo { User = u, Contact = c };

}

return query;

Could result in an exception, because by the time "query" is enumerated, the "db" will have been disposed.  I'm just guessing, but that seems like a plausible explanation to me.

0
Comment actions Permalink

You are correct that it is wrapped within a using statement, but the return is inside the using, not outside. The function works fine; I get the data I need.

0
Comment actions Permalink

You _do_ realize that the position of the return statement doesn't make a difference for the disposal of db?

A using(var db = new Context())
{
     ... some code
}

is equal to

{
     var db = new Context();
     try
     {
          ... some code
     }
     finally
     {
          if(db != null)
               ((IDisposable)db).Dispose();
     }
}

And what happens if you return in the try block? The finally block will be invoked. Anything else would be a desaster for proper memory management.The finally block _guarantees_ that it's invoked, no matter what (return, exception, you name it).

So he was right: you disposed db before using it a second time, and fortunately Resharper is clever enough to tell you, you are clever enough to ask here, but not clever enough to see the answer when it occurs. ;)

0
Comment actions Permalink

I would also point out that your code may very well work just fine, because you've coded it well enough that you avoid the problem.  But that doesn't mean that there isn't a potential for the problem to still occur, especially 2 years from now when someone else has to make a change to the code and doesn't realize that the potential problem is there.  That's why R# is looking out for ya! ;)

0
Comment actions Permalink

Sorry guys, I guess I should have posted the actual whole code (my mistake was to think it was self-understood; I was trying to keep it simple).

 
    public static List<BO.RequestInfo> AllWithContact(int page, int pageSize, out int totalRecords)
    {
      using (var db = Db.New())
      {
        var query = from r in db.Request
                    join u in db.User on r.RequestUserId equals u.UserId
                    from c in db.Contact.Where(p => p.ContactUserId == u.UserId && p.ContactMain).DefaultIfEmpty()
                    orderby r.RequestId descending
                    select new BO.RequestInfo
                    {
                      Request = r,
                      Contact = c
                    };
 
        totalRecords = query.Count();
 
        return query.Skip((page - 1) * pageSize).Take(pageSize).ToList();
      }
    }



That's an actual block of code. All blocks of DB access code follow the same pattern: using wraps data context (Db.New() is a factory method that creates a data context object) and returns some kind of data (list of objects, single object, or some kind of calculation). I never leak the data context outside of the using or anything created inside the using -- that wouldn't even compile since you'd try to use a variable outside of the scope it was declared.

0
Comment actions Permalink

Very interesting, indeed.

So my guess is: Resharper doesn't recognize the .ToList() properly.

Could also be I don't know of some secret stuff that would still allow some closure to leak out of the scope.. hrmm. But can't think of a way right now, maybe the Jetbrains guys have an idea why Resharper is (rightfully?) complaining?

0
Comment actions Permalink

-- doublepost --


0
Comment actions Permalink

It seems like it doesn't like building a left join with two "from" statements in the same linq. Writing var x = (linq statement).ToList() or var x = linq statement; var xlist = x.ToList() doesn't make a difference.

0
Comment actions Permalink

Unfortunately, ReSharper analysis is not smart enough to track that query expression is definitely executed inside "using ..." block. For now, it tracks only in a single expression.
We are going to increase smartness in the future releases :)

0
Comment actions Permalink

Still an issue with Reshaper 2019.2. :-(

0
Comment actions Permalink

Hello Marcus,

 

Could you please share some code sample for which the issue is reproduced? You can do privately via 'Submit a request' form at the top of the page.

Thank you.

 

0
Comment actions Permalink

Still an issue with Reshaper 2019.2. :-(

using (var conn = CreateConnection(ddsDbSettings.DatabaseNameDds))
{
    using (var tr = conn.BeginTransaction(IsolationLevel.ReadCommitted))
    {
        asyncResult = await Task.Run(() => conn.Query<CompareObject>(sql, null, tr)).ConfigureAwait(false);
    }
}

The variable conn is the issue.

0

Please sign in to leave a comment.