simon Whale
simon Whale

Reputation: 61

Entity Framework Core - disposed when trying to run 2nd Query

I have an issue with a database context being disposed. I have set up the databases like the below in the Configure services method. The code has been simplified to hopefully make it easier to read.

public void ConfigureServices(IServicesCollection services)
{
      Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("Database1")));
      Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("Database2")));
      Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("Database3")));
      Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("Database4")));

      Services.AddScoped<IQueryService1, ConcreteService1>();
      Services.AddScoped<IQueryService1, ConcreteService2>();
      Services.AddScoped<IQueryService1, ConcreteService3>();
      Services.AddScoped<IQueryService1, ConcreteService4>();
}

Now in one of the controllers I inject the relevant services that are required.

[Produces("application/json")]
[Route("api/[controller]/[action]
public class DigitalFinesController : Controller
{
      private readonly IQueryService1 _Service1;

      public DigitalFinesController(IConfiguration configuration, IQueryServices1 QueryService1)
      {
         _Service1 = QueryService1;
      }

      [Authorize]
      [HttpPost]
      [ActionName("SubmitFine")]
      [ProducesResponseType(200)]
      [ProducesResponseType(401)]
      public async Task<IActionResult> SubmitFine([FromBody] Models.DigitalFine fine)
      {
         //This is a simple version of my issue
         var vehicles = _Service1.Vehicles.FirstOrDefault(p=> p.vrm == "OX7 DFG");
         if(vehicle == null)
         {
            return BadRequest("Vehicle is missing");
         }

         var fleet = _Service1.Fleets.FirstOrDefault(p=> p.Code = "MyCode");
      }
}

And once I get to the second query I get the following exception

System.ObjectDisposedException: 'Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.

And I am stumped to understand why this is happening. Can anyone please give me a pointer to fix this?

Many thanks Simon

Upvotes: 3

Views: 8678

Answers (2)

Ryan Wilson
Ryan Wilson

Reputation: 10800

.AddScoped will dispose after lifetime of the request, try changing to singleton or transient:

Please see documentation: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.2

At this section:

In the sample app, the IMyDependency service is registered with the concrete type MyDependency. The registration scopes the service lifetime to the lifetime of a single request. Service lifetimes are described later in this topic.

Warning

When using a scoped service in a middleware, inject the service into the Invoke or InvokeAsync method. Don't inject via constructor injection because it forces the service to behave like a singleton. For more information, see ASP.NET Core Middleware.

Upvotes: 1

Zakk Diaz
Zakk Diaz

Reputation: 1093

I think it may have to do with how you're registering it. Try registering it with AddSingleton instead of AddScoped

https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.2#service-lifetimes-and-registration-options

Scoped

Scoped lifetime services are created once per request.

Warning

When using a scoped service in a middleware, inject the service into the Invoke or InvokeAsync method. Don't inject via constructor injection because it forces the service to behave like a singleton. For more information, see ASP.NET Core Middleware.

Singleton

Singleton lifetime services are created the first time they're requested (or when ConfigureServices is run and an instance is specified with the service registration). Every subsequent request uses the same instance. If the app requires singleton behaviour, allowing the service container to manage the service's lifetime is recommended. Don't implement the singleton design pattern and provide user code to manage the object's lifetime in the class.

Warning

It's dangerous to resolve a scoped service from a singleton. It may cause the service to have incorrect state when processing subsequent requests.

Upvotes: 3

Related Questions