Para empezar, esta es una discusión si alguno de ustedes hace algo como la cancelación de solicitudes en los controladores WebAPI (probablemente también aplicable para MVC).
Lo que quiero decir en particular es un escenario como el siguiente: un cliente (normalmente un navegador) inicia una solicitud, se aleja o, más en general, aborta la solicitud por cualquier motivo. Ahora, la solicitud se cancela en el lado del cliente y ya no se considerará. Pero en el lado del servidor, la solicitud aún se está ejecutando y, por lo general, podría estar haciendo dos cosas especialmente interesantes:
Y todo por nada al final (al menos cuando se trata de una operación de lectura sin efectos secundarios al menos).
¿Alguien maneja la cancelación de la consulta/llamada de servicio en curso en tal caso?
Lo que sé es que se puede pasar un CancellationToken en el API-Controller (aunque no pude hacerlo funcionar, por lo que realmente se solicitó la cancelación al cancelar desde el cliente). Este CancellationToken , en teoría, debería transmitirse a todas las capas inferiores para manejar una probable cancelación de llamadas de servicio y base de datos.
Mientras que en el momento de escribir este artículo, WebAPI no admite directamente la cancelación, la API de OWIN sí lo hace. Si usa WebAPI 2.0, se ejecutará sobre OWIN y podrá acceder al contexto a través de los contenedores de Microsoft mediante el método de extensión GetOwinContext() .
Convenientemente, la cancelación se propaga usando un valor CancellationToken expuesto a través de la propiedad CallCancelled de OwinRequest . Puede juntar todo esto para obtener el token dentro de un método de controlador:
public async Task Get() { var cancellation = Request.GetOwinContext().Request.CallCancelled; await database.FooAsync(cancellation); } Aunque eso es bastante feo. Tendrá que hacer esta llamada en cada método que necesite manejar la cancelación y no funciona bien con el futuro propuesto donde WebAPI le dará este CancellationToken . En cambio, ¿no sería mejor si pudiéramos convertir esto en un parámetro?
public async Task Get(CancellationToken cancellation) { await database.FooAsync(cancellation); } Para hacer esto, puede crear un enlace de parámetro personalizado que tome el CancellationToken del contexto OWIN:
public class OwinCancellationTokenBinding : HttpParameterBinding { public OwinCancellationTokenBinding(HttpParameterDescriptor parameter) : base(parameter) { } public override Task ExecuteBindingAsync( ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken) { actionContext.ActionArguments[Descriptor.ParameterName] = actionContext.Request.GetOwinContext().Request.CallCancelled; return Task.FromResult<object>(null); } } Para usar esto, puede registrar el enlace con HttpConfiguration usando su colección ParameterBindingRules :
config.ParameterBindingRules.Add(p => p.ParameterType == typeof(CancellationToken) ? new OwinCancellationTokenBinding (p) : null); Esta regla coincide con cualquier parámetro de tipo CancellationToken . Puede crear cualquier regla aquí que coincida con los parámetros para los que desea que se proporcione este valor.