在使用ConfigureAwait(false)的引用库中使用Thread.CurrentPrincipal的声明是否会造成任何问题,或者ExecutionContext的逻辑调用上下文的流动会在那里照顾我? (到目前为止,我的阅读和测试表明它会)。
示例WebAPI控制器操作:
[CustomAuthorizeThatSetsCurrentUsersClaimsToThreadCurrentContextAndHttpContextCurrentUser]
public async Task<Order> Get(int orderId)
{
return await _orderBusinessLogicLibrary.LoadAsync(orderId); // defaults to .ConfigureAwait(true)
}
来自外部参考库的示例加载函数:
[ClaimsPrincipalPermission(
SecurityAction.Demand,
Operation="Read",
Resource="Orders")]
[ClaimsPrincipalPermission(
SecurityAction.Demand,
Operation="Read",
Resource="OrderItems")]
public async Task<Order> Load(int orderId)
{
var order = await _repository.LoadOrderAsync(orderId).ConfigureAwait(false);
// here's the key line.. assuming this lower-level function is also imposing
// security constraints in the same way this method does, would
// Thread.CurrentPrincipal still be correct inside the function below?
order.Items = await _repository.LoadOrderItemsAsync(orderId).ConfigureAwait(false);
return order;
}
此外,答案不能是“那么不要使用ConfigureAwait(false)!”。这可能会导致其他问题,例如死锁(Don't Block on Async Code)。
答案 0 :(得分:13)
在我的测试中,即使您使用Thread.CurrentPrincipal
,ConfigureAwait(false)
也会正确显示。以下WebAPI代码设置主体,然后阻止async
调用,强制另一个线程恢复async
方法。其他线程确实继承了正确的主体。
private async Task<string> Async()
{
await Task.Delay(1000).ConfigureAwait(false);
return "Thread " + Thread.CurrentThread.ManagedThreadId + ": " + Thread.CurrentPrincipal.Identity.Name + "\n";
}
public string Get(int id)
{
var user = new ClaimsPrincipal(new ClaimsIdentity(
new[]
{
new Claim(ClaimTypes.Name, "Bob"),
}
));
HttpContext.Current.User = user;
Thread.CurrentPrincipal = user;
var ret = "Thread " + Thread.CurrentThread.ManagedThreadId + ": " + Thread.CurrentPrincipal.Identity.Name + "\n";
ret += Async().Result;
return ret;
}
当我在IISExpress的新实例上运行此代码时,我得到:
"Thread 7: Bob\nThread 6: Bob\n"
但是,我应该指出,不建议使用ConfigureAwait(false)
来避免死锁。在ASP.NET上尤其如此。如果可能,请使用ConfigureAwait(false)
并一直使用async
。请注意,WebAPI是一个完全 - async
堆栈,您应能够执行此操作。