EF Core DbContext ObjectDisposedException - PullRequest
       5

EF Core DbContext ObjectDisposedException

0 голосов
/ 06 ноября 2019

EF core 2.2 и .net core 2.2 Я борюсь с такими исключениями ObjectDisposedException, как: здесь и здесь

несколько фактов:

  • все мои сервисы зарегистрированы как временные, то же самое с DbContext с использованием AddDbContext()
  • с использованием DI для внедрения DbContext instance
  • все функции, упомянутые в трассировке стека, async / await

Я чувствую, что здесь упускаю что-то очевидное, но я потратил на это уже 2-3 дня без всякой удачи

трассировка стека:

Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware [8] - An unhandled exception has occurred while executing the request. 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.
Object name: 'BaseContext'.
   at Microsoft.EntityFrameworkCore.DbContext.CheckDisposed()
   at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies()
   at Microsoft.EntityFrameworkCore.DbContext.Microsoft.EntityFrameworkCore.Internal.IDbContextDependencies.get_QueryProvider()
   at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.ParameterExtractingExpressionVisitor..ctor(IEvaluatableExpressionFilter evaluatableExpressionFilter, IParameterValues parameterValues, IDiagnosticsLogger`1 logger, DbContext context, Boolean parameterize, Boolean generateContextAccessors)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryModelGenerator.ExtractParameters(IDiagnosticsLogger`1 logger, Expression query, IParameterValues parameterValues, Boolean parameterize, Boolean generateContextAccessors)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.System.Collections.Generic.IAsyncEnumerable<TResult>.GetEnumerator()
   at System.Linq.AsyncEnumerable.Aggregate_[TSource,TAccumulate,TResult](IAsyncEnumerable`1 source, TAccumulate seed, Func`3 accumulator, Func`2 resultSelector, CancellationToken cancellationToken) in D:\a\1\s\Ix.NET\Source\System.Interactive.Async\Aggregate.cs:line 118
   at Sample.Infrastructure.Tasks.TagEventTypeTasks.GetAllAsync() in ~root\Sample.API\Sample.Infrastructure\Tasks\TagEventTypeTasks.cs:line 24
   at Sample.API.Helpers.GraphHelpers.GetAllTagEventTypesWithCacheAsync() in ~root\Sample.API\Sample.API\Helpers\GraphHelpers.cs:line 45
   at Sample.API.Controllers.GraphController.GetTagEventTypeTimesAsync() in ~root\Sample.API\Sample.API\Controllers\GraphController.cs:line 59
   at lambda_method(Closure , Object )
   at Microsoft.Extensions.Internal.ObjectMethodExecutorAwaitable.Awaiter.GetResult()
   at Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeNextActionFilterAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.Invoke(HttpContext context)

для полной прозрачности, вот методы, упомянутые в трассировке стека:

GraphController.cs:

[HttpGet("tagEventTypeTimes")]
public async Task<ActionResult<List<TagEventTypeResultDto>>> GetTagEventTypeTimesAsync()
{
    return await _graphHelpers.GetAllTagEventTypesWithCacheAsync();
}

GraphHelpers.cs:

public async Task<List<TagEventType>> GetAllTagEventTypesWithCacheAsync()
{
    string tagEventTypesKey = "tagEventTypes";
    List<TagEventType> tagEventTypes;
    if (!_cache.TryGetValue<List<TagEventType>>(tagEventTypesKey, out tagEventTypes))
    {
        tagEventTypes = await _tagEventTypeTasks.GetAllAsync();
        _cache.Set<List<TagEventType>>(tagEventTypesKey, tagEventTypes, _memCacheOptions);
    }

    return tagEventTypes;
}

TagEventTypeTasks.cs:

public class TagEventTypeTasks : ITagEventTypeTasks
{
    private readonly BaseContext _context;

    public TagEventTypeTasks(BaseContext context)
    {
        _context = context;
    }

    public async Task<List<TagEventType>> GetAllAsync()
    {
        return await _context.TagEventType.OrderByDescending(x => x.Id).AsNoTracking().ToListAsync();
    }
}

BaseContext.cs:

public class BaseContext : DbContext
{
    private readonly ILoggerFactory _logger;

    public BaseContext(DbContextOptions<BaseContext> options, ILoggerFactory logger) : base(options)
    {
        _logger = logger;
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseLoggerFactory(_logger);
    }

    public DbSet<Patient> Patient { get; set; }
    public DbSet<Room> Room { get; set; }
    public DbSet<Tag> Tag { get; set; }
    public DbSet<TagEvent> TagEvent { get; set; }
    public DbSet<TagEventType> TagEventType { get; set; }
    public DbSet<TagLocation> TagLocation { get; set; }
    public DbSet<TagRegistration> TagRegistration { get; set; }
    public DbSet<User> User { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.ApplyConfiguration(new PatientConfiguration());
        builder.ApplyConfiguration(new TagConfiguration());
        builder.ApplyConfiguration(new TagRegistrationConfiguration());
        builder.ApplyConfiguration(new TagEventConfiguration());
        builder.ApplyConfiguration(new TagEventTypeConfiguration());
        builder.ApplyConfiguration(new TagLocationConfiguration());
        builder.ApplyConfiguration(new RoomConfiguration());
    }
}

ОБНОВЛЕНИЕ: добавлен код, связанный с запуском

services.AddDbToServices(Configuration.GetConnectionString("DefaultConnection"));

public static void AddDbToServices(this IServiceCollection services, string connectionString)
{
    services.AddDbContext<BaseContext>(options => options.UseFirebird(connectionString), ServiceLifetime.Transient);
}

ОБНОВЛЕНИЕ2

добавлено целое TagEventTypeTasks класс

UPDATE3

регистрация добавленных услуг Я использую эту lib однако я попытался зарегистрировать все службы вручную, используя AddTransient() -> также не помогло

var assembliesToScan = new[]
{
    Assembly.GetExecutingAssembly(),
    Assembly.GetAssembly(typeof(Patient)),
    Assembly.GetAssembly(typeof(PatientTasks))
};

services
    .RegisterAssemblyPublicNonGenericClasses(assembliesToScan)
    .AsPublicImplementedInterfaces(ServiceLifetime.Transient);

1 Ответ

0 голосов
/ 06 ноября 2019

Это похоже на проблему внедрения зависимости.

Я думаю, _graphHelpers удаляет контекст, и в следующий раз, когда выполняется действие, контроллер использует непереходный _graphHelpers, который сохраняется на старомРазмещенный контекст.

Это может быть даже контроллер, вызывающий Dispose() на _graphHelpers.


Некоторые примеры DI

Вот настройка из Начало работы с ASP.NET Core и Entity Framework 6

(...)
services.AddScoped<SchoolContext>(_ => new SchoolContext(Configuration.GetConnectionString("DefaultConnection")

Учебное пособие: начало работы с EF Core в веб-приложении ASP.NET MVC использует AddDbContext Обратите внимание, что этот пример предназначен для .NET Core 2.2, а не 3.0.

(...)
services.AddDbContext<SchoolContext>(options =>
    options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

Вот конфигурация из Настройка DbContext

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<BloggingContext>(options => options.UseSqlite("Data Source=blog.db"));
}

Нет решения DI

Вы можете использовать новый контекст для извлечения данныхне _context.

public async Task<List<TagEventType>> GetAllAsync()
{
    // If you want DI, then do this only Temporarily, just for a diagnosis.
    using (var db = new InverterContext("connString")) 
    {
       return await db.TagEventType.OrderByDescending(x => x.Id).AsNoTracking().ToListAsync();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...