tutorial net example crear como asp apicontroller c# asp.net-mvc-4 asp.net-web-api

c# - example - ASP.NET Web API+Cancelación de operación de larga ejecución



web api rest c# (3)

¿Hay alguna manera de averiguar en ASP.NET Web API beta si la solicitud HTTP fue cancelada (cancelada por el usuario de por cualquier otro motivo)? Estoy buscando la oportunidad de tener un tipo de token de cancelación listo para usar que indicará que la solicitud se ha cancelado y, por lo tanto, las operaciones de ejecución prolongada también deben anularse.

Posible pregunta relacionada: el caso de uso para la clase CancellationTokenModelBinder. ¿Cuál es el motivo para tener una carpeta separada para la ficha de cancelación?


Puede verificar Response.IsClientConnected de vez en cuando para ver si el navegador todavía está conectado al servidor.


Me gustaría resumir un poco. El único enfoque que parece funcionar es comprobar Response.IsClientConnected. Aquí algunos detalles técnicos sobre lo que está pasando detrás del escenario: aquí y aquí. Este enfoque tiene algunos defectos:

  • Funciona solo bajo IIS (sin autohospedaje, sin servidor de desarrollo);
  • Según algunas respuestas de SO, las respuestas pueden ser lentas (no reaccione inmediatamente después de que el cliente se haya desconectado): aquí ;
  • Hay consideraciones con respecto a este costo de llamada: aquí

Al final se me ocurrió la siguiente pieza de código para inyectar CancellationToken basado en IsClientConnected en el controlador de la API web:

public class ConnectionAbortTokenAttribute : System.Web.Http.Filters.ActionFilterAttribute { private readonly string _paramName; private Timer _timer; private CancellationTokenSource _tokenSource; private CancellationToken _token; public ConnectionAbortTokenAttribute(string paramName) { _paramName = paramName; } public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext) { object value; if (!actionContext.ActionArguments.TryGetValue(_paramName, out value)) { // no args with defined name found base.OnActionExecuting(actionContext); return; } var context = HttpContext.Current; if (context == null) { // consider the self-hosting case (?) base.OnActionExecuting(actionContext); return; } _tokenSource = new CancellationTokenSource(); _token = _tokenSource.Token; // inject actionContext.ActionArguments[_paramName] = _token; // stop timer on client disconnect _token.Register(() => _timer.Dispose()); _timer = new Timer ( state => { if (!context.Response.IsClientConnected) { _tokenSource.Cancel(); } }, null, 0, 1000 // check each second. Opts: make configurable; increase/decrease. ); base.OnActionExecuting(actionContext); } /* * Is this guaranteed to be called? * * */ public override void OnActionExecuted(System.Web.Http.Filters.HttpActionExecutedContext actionExecutedContext) { if(_timer != null) _timer.Dispose(); if(_tokenSource != null) _tokenSource.Dispose(); base.OnActionExecuted(actionExecutedContext); } }


Si agregó CancellationToken en los métodos del controlador, el marco lo inyectará automáticamente y, cuando un cliente llame a xhr.abort (), el token se cancelará automáticamente.

Algo similar a

public Task<string> Get(CancellationToken cancellationToken = default(CancellationToken))

Para MVC también puede consultar

HttpContext.Current.Response.IsClientConnected HttpContext.Response.ClientDisconnectedToken

Para .NetCore

services.AddTransient<ICustomInterface>(provider => { var accessor = provider.GetService<IHttpContextAccessor>); accessor.HttpContext.RequestAborted; });