AspNetSynchronizationContext
Пытаясь использовать новую асинхронную модель С# 5, мне было удивительно, что AspNetSynchronizationContext
является внутренним классом (а также базой AspNetSynchronizationContextBase
). Таким образом, недокументировано. Но важно знать, что он делает, используя функцию async/await в вашем коде ASP.NET. Я исправлю это
гарантирует, что ваши продолжения получат те же HttpContext.Current
, что и исходные абоненты?
Он не гарантирует, что продолжения будут выполняться в том же потоке, что и вызывающие?
Если последнее предположение неверно, и я получаю исходный поток, могу ли я получить тот же контекст потока в продолжениях? Я имею в виду главную/культуру, связанную с локальным хранилищем потоков и потоков? Это важно, потому что локализация ASP.NET основана на культуре потоков, и мое приложение использует модель безопасности роли .NET(директив потоков).
Ответы
Ответ 1
Я исправляю, что он гарантирует, что ваши продолжения получат тот же HttpContext.Current, что и исходные вызывающие? Это не гарантирует продолжения выполнения в том же потоке, что и вызывающие?
Да, HttpContext.Current
сохраняется, и да, продолжения могут выполняться в другом потоке.
Я имею в виду главный/культ, связанный с локальным хранилищем потоков и потоков? Это важно, потому что локализация ASP.NET основана на культуре потоков, и мое приложение использует модель безопасности роли .NET(директив потоков).
Обычное локальное хранилище данных теряется. Вы можете уменьшить это, используя LogicalCallContext
(который течет с помощью ExecutionContext
), но с async
проще просто ссылаться на переменные напрямую.
Принципал всегда сохраняется; иначе было бы угрозой безопасности. Это происходит с помощью ExecutionContext
.
Я считаю, что культура течет с AspNetSynchronizationContext
, но я не тестировал это на .NET 4.5 новой реализации.
Вы можете найти мою статью MSDN на SynchronizationContext
. Это не официальная документация (я не работаю для Microsoft), но, по крайней мере, это что-то. Обратите внимание, что AspNetSynchronizationContext
, на который ссылается в этой статье, теперь называется LegacyAspNetSynchronizationContext
в .NET 4.5.
Еще один отличный ресурс - Stephen Toub ExecutionContext
vs. SynchronizationContext
.
Ответ 2
Хорошо, что захват ExecutionContext всегда гарантирован, захват и выполнение выполнения в том же SynchronizationContext зависит от Awaiter.
Самый распространенный awaiter (тип, возвращаемый методом GetAwaiter(), который внутренне вызывается, когда вы "ждёте" что-то), является TaskAwaiter, возвращаемым Task.GetAwaiter(). По умолчанию TaskAwaiter захватит текущий SynchronizationContext и запустит делегат продолжения на захваченном SynchronizationContext. Это означает, что вы сможете использовать HttpContext.Current в остальной части вашего метода, и вы не против, чтобы он выполнялся как продолжение. Таким образом, этот код будет работать так, как ожидалось (часть, где вы записываете "B", будет запускаться в том же контексте synchronizationcontext, что и первая строка):
HttpContext.Current.Response.Write("A");
await Task.Delay(1000);
HttpContext.Current.Response.Write("B")
Вы можете изменить это поведение с помощью метода Task.ConfigureAwait(false)
, который сообщает awaiter не помещать остальную часть метода обратно в исходный SynchronizationContext.
Конечно, если вы используете Task.Run или Task.Factory.StartNew в асинхронном методе, который вы вызываете, это ваша обязанность снова захватить SynchronizationContext.
Желаем удачи.