HttpContext.Current null внутри задачи async

У меня есть метод, который использует репозиторий (userRepo):

    public override Task<IdentityResult> CreateLocalUserAsync(IUser user, string password, CancellationToken cancellationToken)
    {
        var task = new Task<IdentityResult>(() => {

            TUserEntity newUser = new TUserEntity
            {
                Id = user.Id,
                UserName = user.UserName,
                Password = password
            };

            userRepo.Save(newUser).Flush();

            return new IdentityResult(true);
        }, cancellationToken);

        task.Start();

        return task;
    }

Объект userRepo имеет зависимость, которая использует HttpContext.Current. Оба они разрешены с помощью ninject InRequestScope.

Вышеуказанный метод вызывается внутри стандартного AccountController в Mvc 5:

var result = await IdentityManager.Users.CreateLocalUserAsync(user, model.Password);

Я попытался добавить этот параметр в web.config:

<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />

Кроме того, я определенно использую .NET 4.5. Это также в моем web.config:

<httpRuntime targetFramework="4.5" />

Невозможно получить информацию из HttpContext до запуска задачи, потому что зависимость userRepo в задаче использует информацию, и оба объекта разрешаются с помощью Ninject.

Как я могу гарантировать, что HttpContext.Current не будет null?

Ответ 1

"Конкретный контекст синхронизации задач" здесь относится к продолжению из await: что бы вы ни делали с result, он будет иметь http-контекст. Однако это не относится к task.Start. Это относится к TaskScheduler, а не к контексту синхронизации.

В принципе, выполняя это на рабочем месте, вы (в процессе, как следствие) разводя этот рабочий из http-контекста. Вы должны:

  • получить необходимую информацию из http-контекста и передать это в рабочий, или
  • не использовать рабочего

Лично я сомневаюсь, что вы набираете много, нажимая это на рабочего. Если вы действительно хотите пойти async, идеальным было бы для вашего репо, чтобы внутренне поддерживать методы *Async. Для этого требуется больше, чем использование потоков: обычно это означает изменения архитектуры, например, используя методы async SQL. Что-то, написанное с нуля для использования async и продолжений, поддерживающих синхронизацию контекста (aka await), автоматически сохранит такие вещи, как http-context.

Важное отличие здесь в том, что реализация async/await является линейной, но не непрерывной, т.е.

 <===(work)==>
                    <===(callback; more work)===>
                                                     <===(another callback)===>

где-то, поскольку ваш существующий код потенциально выполняет действия параллельно, т.е.

<==========(original work)=================>
         <===========(task on worker thread)=============>

Тот факт, что подход async/await в основном линейный, делает его гораздо более подходящим для доступа к таким вещам, как http-context, поскольку он знает, что (сделано правильно) будет только один поток при доступе к времени он - даже если это не тот же поток от конца до конца.