async-await - practices - call async method c# await
Seguridad, Thread.CurrentPrincipal y ConfigureAwait(falso) (1)
Según mis pruebas, parece que Thread.CurrentPrincipal
fluirá correctamente, incluso si usa ConfigureAwait(false)
. El siguiente código WebAPI establece el principal y luego bloquea en una llamada async
, lo que obliga a otro hilo a reanudar el método async
. Ese otro hilo hereda el principal correcto.
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;
}
Cuando ejecuto este código en una nueva instancia de IISExpress, obtengo:
"Thread 7: Bob/nThread 6: Bob/n"
Sin embargo, debo señalar que no se recomienda usar ConfigureAwait(false)
para evitar el interbloqueo. Esto es especialmente cierto en ASP.NET. Si es posible, use ConfigureAwait(false)
y también use async
hasta el final. Tenga en cuenta que WebAPI es una pila totalmente async
y debería poder hacer esto.
¿El uso de las afirmaciones de Thread.CurrentPrincipal en una biblioteca referenciada que utiliza ConfigureAwait (falso) plantea algún problema o el flujo del contexto de llamada lógica de ExecutionContext me ocupará allí? (mi lectura y prueba hasta el momento indican que sí).
Ejemplo de acción del controlador WebAPI:
[CustomAuthorizeThatSetsCurrentUsersClaimsToThreadCurrentContextAndHttpContextCurrentUser]
public async Task<Order> Get(int orderId)
{
return await _orderBusinessLogicLibrary.LoadAsync(orderId); // defaults to .ConfigureAwait(true)
}
Ejemplo de funciones de carga desde una biblioteca externa referenciada:
[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;
}
Además, la respuesta no puede ser "¡bueno, no uses ConfigureAwait (falso)!". Eso puede causar otros problemas, como interbloqueo ( No bloquear en código Async ).