Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot access a disposed object in ASP.NET Core when injecting DbContext

On an ASP.NET Core project I have the following on Startup:

  services.AddDbContext<Context>(x => x.UseSqlServer(connectionString));    services.AddTransient<IValidationService, ValidationService>();    services.AddTransient<IValidator<Model>, ModelValidator>(); 

The ValidationService is as follows:

public interface IValidationService {     Task<List<Error>> ValidateAsync<T>(T model); }  public class ValidationService : IValidationService {     private readonly IServiceProvider _provider;      public ValidationService(IServiceProvider provider) {         _provider = provider;     }      public async Task<List<Error>> ValidateAsync<T>(T model) {         IValidator<T> validator = _provider.GetRequiredService<IValidator<T>>();          return await validator.ValidateAsync(model);     } } 

And the ModelValidator is as follows:

public class ModelValidator : AbstractValidator<Model> {   public ModelValidator(Context context) {     // Some code using context   } } 

When I inject a IValidationService in a controller and use it as:

List<Error> errors = await _validator.ValidateAsync(order);     

I get the error:

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 is 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. Object name: 'Context'.

Any idea why I am having this error when using Context inside ModelValidator.

How to fix this?

UPDATE

So I changed the code to:

services.AddScoped<IValidationService, ValidationService>();  services.AddScoped<IValidator<Model>, ModelValidator>(); 

But I get the same error ...

UPDATE - Seed Data Code inside Configure method on Startup

So on Configure method I have:

if (hostingEnvironment.IsDevelopment())   applicationBuilder.SeedData(); 

And the SeedData extension is:

public static class DataSeedExtensions {     private static IServiceProvider _provider;      public static void SeedData(this IApplicationBuilder builder) {          _provider = builder.ApplicationServices;         _type = type;          using (Context context = (Context)_provider.GetService<Context>()) {             await context.Database.MigrateAsync();             // Insert data code     } } 

What am I missing?

UPDATE - A possible solution

Changing my Seed method to the following seems to work:

using (IServiceScope scope =      _provider.GetRequiredService<IServiceScopeFactory>().CreateScope()) {     Context context = _provider.GetService<Context>();     // Insert data in database } 
like image 714
Miguel Moura Avatar asked Aug 01 '16 16:08

Miguel Moura


People also ask

Should you use using with dbContext?

EF and EF Core DbContext types implement IDisposable . As such, best practice programming suggests that you should wrap them in a using() block (or new C# 8 using statement). Unfortunately, doing this, at least in web apps, is generally a bad idea.

Is dbContext scoped?

This example registers a DbContext subclass called ApplicationDbContext as a scoped service in the ASP.NET Core application service provider (a.k.a. the dependency injection container). The context is configured to use the SQL Server database provider and will read the connection string from ASP.NET Core configuration.


2 Answers

Just a guess in what causes your error:

You are using DI and async calls. If, somewhere in your call stack, you return a void instead of Task, you get the described behavior. At that point, the call is ended and the context disposed. So check if you have an async call that returns a void instead of Task. If you change the return value, the ObjectDisposedException is probably fixed.

public static class DataSeedExtensions { private static IServiceProvider _provider;  public static async Task SeedData(this IApplicationBuilder builder) { //This line of code    _provider = builder.ApplicationServices;   _type = type;    using (Context context = (Context)_provider.GetService<Context>()) {      await context.Database.MigrateAsync();     // Insert data code    }  } 

And in configure:

if (hostingEnvironment.IsDevelopment()){    await  applicationBuilder.SeedData(); } 

Blog post on how to fix this error: Cannot access a disposed object in ASP.NET Core when injecting DbContext

like image 93
Peter Avatar answered Sep 21 '22 02:09

Peter


I had a similar issue working with asp.net core. I have an async POST method in my controller and when it returns void I will have this exception. After I changed the POST method return a TASK the problem was solved.

Change from:

public async void PostAsync([FromBody] Model yourmodel) 

To

public async Task PostAsync([FromBody] Model yourmodel) 
like image 28
Yang Zhang Avatar answered Sep 23 '22 02:09

Yang Zhang