Entity Framework 6 "DbContext has been disposed" exception

时间:2016-10-20 13:08:55

标签: asp.net-web-api entity-framework-6

Something very strange is happening in production, and it only happens in production. I have a Web API running and in one of the APIs, there is a repository created in the constructor and used in the functions. This is how the flow of a request works:

  1. HTTP request comes in
  2. MVC API controller decides which "worker" class to instantiate and creates it using Activator.CreateInstance
  3. API controller calls worker.OnExecute inside of a Task.Run() and returns the http response
  4. Worker calls _engine.Execute

Each worker instantiates another "engine" class that has all of the logic. The engine in case constructs 3 repositories created using a UnitOfWork that is created per engine instance, like so:

public class MyWorker : Worker
{
    private readonly MyEngine _engine;

    public MyWorker()
    {
        _engine = new MyEngine();
    }

    protected override WorkerResult OnExecute(JObject data, CancellationToken cta)
    {
        return new WorkerResult(HttpStatusCode.OK, _engine.Execute(data));
    }
}

public class MyEngine : EngineBase
{
    private BaseRepository<Order> OrderRepo { get; set; }
    private BaseRepository<OrderItem> OrderItemRepo { get; set; }

    public MyEngine()
    {
        OrderRepo = new BaseRepository<Order>(MyUnitOfWork);
        OrderItemRepo = new BaseRepository<OrderItem>(MyUnitOfWork);
    }

    public string Execute(JObject data)
    {
        return IsOrderValid(data).ToString();
    }

    public bool IsOrderValid(JObject data)
    {
        var orderId = data.Value<int>("OrderId");

        // Without this line it crashes. With this line it crashes
        //OrderRepo = new BaseRepository<Order>(InternationalWork);

        // This is where it crashes
        Order order = OrderRepo.First(x => x.OrderID == orderId);
        // more code
    }
}

public class EngineBase : UnitOfWorker, IDisposable
{
    private UnitOfWork _myUnitOfWork;

    public EngineBase() { }

    public UnitOfWork MyUnitOfWork
    {
        get
        {
            return _myUnitOfWork ?? (_myUnitOfWork = new UnitOfWork(new DbContextAdapter(new MyDbContext())));
        }
    }
}

This is the actual stack trace:

The operation cannot be completed because the DbContext has been disposed.
StackTrace1 
  at System.Data.Entity.Internal.LazyInternalContext.InitializeContext() 
  at System.Data.Entity.Internal.LazyInternalContext.get_ObjectContext() 
  at System.Data.Entity.Internal.Linq.InternalSet`1.CreateObjectQuery(Boolean asNoTracking, Nullable`1 streaming, IDbExecutionStrategy executionStrategy) 
  at System.Data.Entity.Internal.Linq.InternalSet`1.InitializeUnderlyingTypes(EntitySetTypePair pair) 
  at System.Data.Entity.Internal.Linq.InternalSet`1.get_InternalContext() 
  at System.Data.Entity.Infrastructure.DbQuery`1.System.Linq.IQueryable.get_Provider() 
  at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source, Expression`1 predicate) 

The stack trace shows "FirstOrDefault" because OrderRepo.First internally calls DbSet.FirstOrDefault, like so:

public virtual T First(Expression<Func<T, bool>> query)
{
    return _dbSet.FirstOrDefault(query);
}

I'm stumped because each worker is created per http request. Each DBContext is created per engine instance so I don't know how it could be disposed when it was just created in the constructor. And this only happens on the production web server where I presume it's being called more. Any tips would be greatly appreciated.

0 个答案:

没有答案