Search code examples
c#entity-frameworkasp.net-web-apientity-framework-6

How to check DBContext is disposed or not?


I want to share a DB context with another method called from outside (inherited class) without creating a new context unless it is being disposed. I want to check the context is disposed so that I could create new context.

It's rest api. There is a bulk upload for multiple entities and I want to share the transaction so if one fail, it will not be committed to DB


Solution

  • Regardless of the comments questioning design quality, valid scenarios exist were the dbContext could be in a disposed state, such as (not a complete list):

    For example (within injected dbContext MVC services):

    1. your service iterates though a lower tier of one-or-more service calls, possibly using asynchronous socket handler on a lower tier API library, with each response using the parent requester dbContext.
    2. Your service calls a database job, (asynchronous task or not).
    3. Exception handling logging to database (if the dbContext is already lost - avoid loss of logging debug details)

    Note: Long running processes using dbContext like this should follow good practice of avoiding dbContext bloat such as using AsNoTracking() method were possible - as bloat can quickly become a concern.

    Performance consideration: Most trusted option is to recreate the dbContext on each child (api call/async task), but this may incur undesired performance overheads, such as when dealing with 1000's of api iterative calls and atomic unit transactions are not viable.

    Solution Tested Using Framework: Entity Type: Microsoft.EntityFrameworkCore.DbContext Version=5.0.16.0, Culture=neutral, PublicKeyToken=adb9793829ddae60

    Warnings: Lots of warning advice available on this type of extended dbContext use, such use should be used with caution/avoided where possible. See warning details : c-sharp-working-with-entity-framework-in-a-multi-threaded-server

    Extend you DbContext with partial class Or add method to your existing extended partial class.

    FYI - Please comment if still working on updated EntityFrameworkCore libraries.

    public partial class FooDbContext : DbContext
    {
    
        // Using Type: 5.0.16.0  EntityFrameworkCore.DbContext (confirm if working with any core library upgrades)
        
        public bool IsDisposed()
        {
            bool result = true;            
            var typeDbContext = typeof(DbContext);
            var isDisposedTypeField = typeDbContext.GetField("_disposed", BindingFlags.NonPublic | BindingFlags.Instance);
    
            if (isDisposedTypeField != null)
            {
                result = (bool)isDisposedTypeField.GetValue(this);
            }
    
            return result;
        }
    }
    

    Usage:

    if (fooDbContext == null || fooDbContext.IsDisposed())
    {
        // Recreate context
    }