Ответ 1
Как интересно! Похоже, что Thread.CurrentPrincipal
основан на контексте логического вызова, а не на контексте вызовов для потоков. ИМО это совершенно неинтуитивно, и мне было бы интересно узнать, почему это было реализовано таким образом.
В .NET 4.5., async
методы взаимодействуют с контекстом логического вызова, так что он будет более корректно работать с методами async
. У меня есть запись в блоге; AFAIK, это единственное место, где оно задокументировано. В .NET 4.5, в начале каждого метода async
, он активирует поведение "copy-on-write" для контекста логического вызова. Когда (если) изменяется контекст логического вызова, он сначала создает локальную копию.
Вы можете увидеть "локальность" контекста логического вызова (то есть, была ли она скопирована), наблюдая System.Threading.Thread.CurrentThread.ExecutionContextBelongsToCurrentScope
в окне просмотра.
Если вы не Yield
, то при установке Thread.CurrentPrincipal
вы создаете копию контекста логического вызова, который рассматривается как "локальный" для этого метода async
. Когда метод async
возвращается, этот локальный контекст отбрасывается и исходный контекст занимает свое место (вы можете видеть ExecutionContextBelongsToCurrentScope
, возвращающийся на false
).
С другой стороны, если вы выполняете Yield
, то поведение SynchronizationContext
берет верх. На самом деле происходит то, что HttpContext
фиксируется и используется для возобновления обоих методов. В этом случае вы не видите Thread.CurrentPrincipal
, сохраненный от AuthenticateAsync
до GetAsync
; то, что на самом деле происходит, HttpContext
сохраняется, а затем HttpContext.User
перезаписывает Thread.CurrentPrincipal
до возобновления методов.
Если вы переместите Yield
в GetAsync
, вы увидите аналогичное поведение: Thread.CurrentPrincipal
рассматривается как локальная модификация с областью AuthenticateAsync
; он возвращает значение, когда возвращается этот метод. Тем не менее, HttpContext.User
по-прежнему устанавливается правильно, и это значение будет записано Yield
, и когда метод возобновится, он перезапишет Thread.CurrentPrincipal
.