Задать вопрос
Timur2342
@Timur2342

Почему я получаю ObjectDisposedException из за DbContext-а? Когда он очищается?

Беру и получаю:
System.ObjectDisposedException: Cannot access a disposed context instance. A common cause of this error is disposing a context instance 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 instance, or wrapping it in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.

Я должен получать System.ObjectDisposedException если делаю операции над очищенным объектом, но db контексты я никак не очищал.
Да и вобще не понятно, я просто юзаю builder.Services.AddDbContext в Program.cs.

Метод в котором получаю exception:
public async Task HasBeenSuccesfullyWorked(long id)
    {
        await StatusUpdate(id, TaskStatus.SuccessCompleted, true, TaskStatus.Working);
        //TaskService.cs:line 94
    }
    private async Task StatusUpdate(long id, TaskStatus newStatus, bool wasCompleted = false,
        TaskStatus? filter = null)
    {
        Expression<Func<TaskEntity, bool>> filterFunc = filter == null
            ? x => x.Id == id
            : x => x.Id == id && x.Status.ToString() == filter.ToString();

        //Где получаю exception
        var foundTask = await dbContext.Tasks.FirstOrDefaultAsync(filterFunc);
        //TaskService.cs:line 127
        //Где получаю exception

        if (foundTask == null)
        {
            logger.LogCritical("The Task Service has not found the task-{x}", id);
            throw new TaskStatusWasNotUpdatedException(id);
        }

        foundTask.Status = newStatus;
        if (wasCompleted) foundTask.CompletedAt = DateTime.UtcNow;

        await dbContext.SaveChangesAsync();
    }

Где вызывается сервис EmailSenderListener.cs:line 64:
public async Task JobWasExecuted(IJobExecutionContext context, JobExecutionException? jobException,
        CancellationToken cancellationToken)
    {
        if (cancellationToken.IsCancellationRequested)
            return;

        var taskId = GetTaskId(context);

        if (jobException != null
            && jobException.InnerException != null)
        {
            _logger.LogError(jobException.InnerException,
                $"{jobException.InnerException.Message}, taskId: {taskId}");

            await _taskService.HasBeenGottenErrors(taskId, jobException.Message);
        }
        else
        {
            _logger.LogInformation("The EmailSender job executed, taskId: {x}", taskId);
            await _taskService.HasBeenSuccesfullyWorked(taskId); //EmailSenderListener.cs:line 64
        }
    }
    private static long GetTaskId(IJobExecutionContext context)
    {
        return context.JobDetail.JobDataMap
            .GetValueOrThrowException<long>("task-id");
    }

И вот не понятно, что делать то? Ранее читал что у человека в stackoverflow такая же проблема была с контекстом, только дело было вобще в том что он не запуска await-ом асинхронный метод сервиса, когда я запускаю(юзаю await проще говоря).

Буду благодарен за любой ответ что поможет мне!
  • Вопрос задан
  • 51 просмотр
Подписаться 1 Простой 1 комментарий
Решения вопроса 1
@mvv-rus
Настоящий админ AD и ненастоящий программист
Я не вижу откуда у вас вызывается JobWasExecuted, поэтому ответ пока будет чисто теоретический. Контекст БД (потомок DbContext), получаемый из контейнера DI в настроке по умолчанию (как у вас, судя по написанному), имеет время жизни Scoped. То есть, при обработке запросов к веб-серверу он создается отдельно для каждого запроса и очищается при завершении обработки этого запроса.

Просто так взять и обратиться к такому контексту из других частей программы, которые могут работать независимо от обработчика запроса (например, из фонового сервиса) нельзя: после завершения запроса получите именно такую ошибку.

Так что, если вам нужно получить контекст БД с нестандартным временем жизни, придется отказаться от получения его через DI со стандартной настройкой.

Время жизни контекста, получаемого через DI, можно изменить, но тут надо хорошо понимать, что и как вы делаете. Например, к DbContext нельзя обращаться параллельно из нескольких потоков - но при типичной обработки запроса такого и не случается. Так что у меня есть сомнение что вам стоит менять штатную настройку.

Штатным способом получения контекстов с нестандартным временем жизни является сервис фабрики на базе DbContextFactory (его тоже можно получить через DI, как - см. документацию). Но следить за временем жизни такого контекста вам придется самостоятельно.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы