The code below was added to a freshly created Visual Studio 2012 .NET 4.5 WebAPI project.
I'm trying to assign both HttpContext.Current.User and Thread.CurrentPrincipal in an asynchronous method. The assignment of Thread.CurrentPrincipal flows incorrectly unless an await Task.Yield(); (or anything else asynchronous) is executed (passing true to AuthenticateAsync() will result in success).
Why is that?
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[] {})
{
}
}
}
}
Notes:
- The
await Task.Yield();can appear anywhere inAuthenticateAsync()or it can be moved intoGetAsync()after the call toAuthenticateAsync()and it will still succeed. ApiController.UserreturnsThread.CurrentPrincipal.HttpContext.Current.Useralways flows correctly, even withoutawait Task.Yield().Web.configincludes<httpRuntime targetFramework="4.5"/>which impliesUseTaskFriendlySynchronizationContext.- I asked a similar question a couple days ago, but did not realize that example was only succeeding because
Task.Delay(1000)was present.