次のコードは、新しく作成したVisual Studio 2012 .NET 4.5 WebAPIプロジェクトに追加されました。Thread.CurrentPrincipalが正しく流れるために、「Wait Task.Yield()」が必要ですか?
HttpContext.Current.User
とThread.CurrentPrincipal
の両方を非同期方式で割り当てようとしています。 await Task.Yield();
(またはその他の非同期のもの)が実行されない限り、Thread.CurrentPrincipal
の割り当ては正しく流れません(true
〜AuthenticateAsync()
を成功させる)。
なぜですか?
using System.Security.Principal;
using System.Threading.Tasks;
using System.Web.Http;
namespace ExampleWebApi.Controllers
{
public class ValuesController : ApiController
{
public async Task GetAsync()
{
await AuthenticateAsync(false);
if (!(User is MyPrincipal))
{
throw new System.Exception("User is incorrect type.");
}
}
private static async Task AuthenticateAsync(bool yield)
{
if (yield)
{
// Why is this required?
await Task.Yield();
}
var principal = new MyPrincipal();
System.Web.HttpContext.Current.User = principal;
System.Threading.Thread.CurrentPrincipal = principal;
}
class MyPrincipal : GenericPrincipal
{
public MyPrincipal()
: base(new GenericIdentity("<name>"), new string[] {})
{
}
}
}
}
注:
- は
await Task.Yield();
はAuthenticateAsync()
のどこにでも現れることができるか、それがAuthenticateAsync()
を呼び出した後GetAsync()
に移動することができ、それはまだ成功します。 ApiController.User
は、Thread.CurrentPrincipal
を返します。HttpContext.Current.User
は、await Task.Yield()
がなくても常に正しく流れます。Web.config
は、<httpRuntime targetFramework="4.5"/>
,impliesUseTaskFriendlySynchronizationContext
を含む。- 私は偶数日前にa similar questionと尋ねましたが、
Task.Delay(1000)
が存在していたため、その例が成功しただけであることに気づいていませんでした。
あなたがそれを忘れた場合はどうなりますか? – SLaks
@SLaks 'await Task.Yield()'がスキップされた場合、 'Thread.CurrentPrincipal'は' await AuthenticateAsync() 'を呼び出す前の状態に戻ります。 'Thread.CurrentPrincipal'はもはや' MyPrincipal'ではないので、例外がスローされます。 –
私のOwinミドルウェアでは、単にTask.Yield()を待っている最後のミドルウェアにチェーンを張らなければなりませんでした。 これは、Thread.CurrentPrincipalを実行中に後で期待どおりにするように思えます。 – BrettJ