asp.net 4.5中有一个新的应用程序设置
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
Run Code Online (Sandbox Code Playgroud)
像这样的代码可以在asp.net 4.0中运行
protected void Button1_Click(object sender, EventArgs e)
{
CallAysnc();
}
public void CallAysnc()
{
AsyncOperation asyncOp = AsyncOperationManager.CreateOperation(Guid.NewGuid().ToString());
WebClient client = new WebClient();
client.DownloadStringCompleted += (object sender, DownloadStringCompletedEventArgs e) =>
{
asyncOp.PostOperationCompleted(CallCompleted, e.Result);
};
client.DownloadStringAsync(new Uri("http://www.google.com"));
}
private void CallCompleted(object args)
{
Response.Write(args.ToString());
}
Run Code Online (Sandbox Code Playgroud)
但它在asp.net 4.5中不起作用,当我删除新的appsetting时,它再次起作用!
那么"UseTaskFriendlySynchronizationContext"的含义是什么?
下面的代码已添加到新创建的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 …Run Code Online (Sandbox Code Playgroud) 在身份验证期间使用ASP.NET WebAPI进行Thread.CurrentPrincipal设置,以便控制器稍后可以使用该ApiController.User属性.
如果该身份验证步骤变为异步(以咨询另一个系统),CurrentPrincipal则会丢失任何变异(当调用者await恢复同步上下文时).
这是一个非常简化的示例(在实际代码中,身份验证发生在动作过滤器中):
using System.Diagnostics;
using System.Security.Principal;
using System.Threading;
using System.Threading.Tasks;
public class ExampleAsyncController : System.Web.Http.ApiController
{
public async Task GetAsync()
{
await AuthenticateAsync();
// The await above saved/restored the current synchronization
// context, thus undoing the assignment in AuthenticateAsync().
Debug.Assert(User is GenericPrincipal);
}
private static async Task AuthenticateAsync()
{
// Save the current HttpContext because it's null after await.
var currentHttpContext = System.Web.HttpContext.Current;
// Asynchronously determine identity.
await Task.Delay(1000);
var …Run Code Online (Sandbox Code Playgroud) 在使用ConfigureAwait(false)的引用库中使用Thread.CurrentPrincipal的声明会造成任何问题,或者ExecutionContext的逻辑调用上下文的流动会在那里照顾我吗?(到目前为止,我的阅读和测试表明它会).
示例WebAPI控制器操作:
[CustomAuthorizeThatSetsCurrentUsersClaimsToThreadCurrentContextAndHttpContextCurrentUser]
public async Task<Order> Get(int orderId)
{
return await _orderBusinessLogicLibrary.LoadAsync(orderId); // defaults to .ConfigureAwait(true)
}
Run Code Online (Sandbox Code Playgroud)
来自外部引用库的示例加载函数:
[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;
}
Run Code Online (Sandbox Code Playgroud)
此外,答案不能是"那么不要使用ConfigureAwait(false)!".这可能会导致其他问题,例如死锁(请勿在异步代码上阻止).
claims-based-identity synchronizationcontext async-await current-principal executioncontext