0

I am getting the following error when using DbContext injected into a service from another service:

ObjectDisposedException: Cannot access a disposed object.

The lifetime of my DbContext is Scoped and the lifetimes of my services is Transient, but changing these other than to Singleton (which we don't want) does not solve the issue.

Interestingly, the error occurs seemingly at random. Sometimes there are no errors and everything runs fine.

In relation to this error, I am (also randomly) getting a InvalidOperationException right after startup, when my Angular app starts firing requests to the backend.
"An attempt was made to use the context while it is being configured. A DbContext instance cannot be used inside OnConfiguring since it is still being configured at this point."

My code:

public class MyService1 {

    private static IMyService2 _myService2;

    public MyService1(IMyService2 myService2){
        _myService2 = myService2;
    }

    public async Task DoSomethingWithMyService2() {
        await _myService2.DoSomething(new MyEntity());
    }
}
public class MyService2 : IMyService2 {

    private MyDbContext _dbContext;

    public MyService2(MyDbContext myDbContext) {
        _dbContext = myDbContext;
    }

    public async Task DoSomething(MyEntity myEntity) {
        await _dbContext.MySet.AddAsync(myEntity); // <-- ObjectDisposedException
        await _dbContext.SaveChangesAsync();
    }
}
veuncent
  • 1,599
  • 1
  • 20
  • 17

1 Answers1

0

To answer my own question: the culprit is that MyService2 is stored in a static field after injection into MyService1.

Because the lifetime of DbContext is Scoped, it will be disposed after an initial request to the service. However, the service will live on during the lifetime of the entire app, with a reference to its disposed DbContext.

(I am not entirely sure about the latter (regarding lifetime of the app), because MyService1 itself is also Transient. Perhaps someone else can explain how that works.)

veuncent
  • 1,599
  • 1
  • 20
  • 17
  • The lifetimes are described on [this page](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.1#service-lifetimes). `Transient` means that a new instance is created every time it's injected. – Métoule Jun 04 '20 at 12:50
  • Thanks. I rather meant that I wasn't sure how a static field behaves in a Transient service. Normally a static class is created once, when an app starts (right?), but I imagine a field inside a class works differently? – veuncent Jun 04 '20 at 13:07
  • There are [many](https://stackoverflow.com/q/3965976/2698119) [questions](https://stackoverflow.com/q/710793/2698119) regarding the lifetime of a static fields, but one of the goal of the dependency injection mechanism is to remove the need for static objects because you can simply have all dependencies injected in the constructor, without needing to know where they come from. Is there a reason why you need a static field for S2? – Métoule Jun 04 '20 at 15:41
  • 1
    No reason, other than that The Previous Guy wrote it that way and I overlooked it while debugging the exception. – veuncent Jun 04 '20 at 15:54