"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.
1
12 comments
Avatar
Permanently deleted user

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
Avatar
Permanently deleted user

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
Avatar
Permanently deleted user

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
Avatar
Permanently deleted user

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
Avatar
Permanently deleted user

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
Avatar
Permanently deleted user

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
Avatar
Permanently deleted user

-- doublepost --


0
Avatar
Permanently deleted user

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

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
Avatar
Permanently deleted user

Still an issue with Reshaper 2019.2. :-(

0

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
Avatar
Permanently deleted user

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.