【发布时间】:2013-05-15 05:37:59
【问题描述】:
以下代码已添加到新创建的 Visual Studio 2012 .NET 4.5 WebAPI 项目中。
我正在尝试以异步方法同时分配 HttpContext.Current.User 和 Thread.CurrentPrincipal。 Thread.CurrentPrincipal 的分配不正确,除非执行 await Task.Yield();(或其他任何异步操作)(将 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,如果
await Task.Yield()被跳过,Thread.CurrentPrincipal将恢复到调用await AuthenticateAsync()之前的状态。由于Thread.CurrentPrincipal不再是MyPrincipal,因此抛出异常。 -
在我的 Owin 中间件中,我必须链接最后一个中间件,它只是等待 Task.Yield();这似乎会导致 Thread.CurrentPrincipal 在整个执行过程中按预期运行。
标签: c# asp.net-web-api async-await