API Web ASP.NET + cancelación de la operación de larga ejecución

votos
11

¿Hay una manera de averiguar en ASP.NET Web API beta si la petición HTTP fue cancelada (abortado por el usuario de cualquier otra razón)? Busco oportunidad de tener un tipo de token de cancelación fuera de la caja que señalará que la solicitud se aborta y ops, por tanto, a largo para correr debería abortarse también.

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

Publicado el 18/03/2012 a las 19:28
fuente por usuario
En otros idiomas...                            


3 respuestas

votos
7

Se puede comprobar Response.IsClientConnectedde vez en cuando para ver si el navegador está todavía conectado al servidor.

Respondida el 19/03/2012 a las 06:20
fuente por usuario

votos
8

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

  • Sólo funciona bajo IIS (sin autoalojamiento, sin Dev Server);
  • Según algunas respuestas SO puede ser lento (no reaccionan inmediatamente después el cliente está desconectado): aquí ;
  • Hay consideraciones con respecto a este coste de la llamada: aquí

Al final se me ocurrió con el siguiente fragmento 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);
    }
}
Respondida el 19/03/2012 a las 13:43
fuente por usuario

votos
0

Si ha añadido CancellationToken en los métodos de controlador, se inyecta automáticamente por el marco, y cuando un cliente llama a xhr.abort () el token se cancelará automáticamente

Algo similar a

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

Para MVC también se puede referir a

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

para .NetCore

services.AddTransient<ICustomInterface>(provider => { 
     var accessor = provider.GetService<IHttpContextAccessor>);
     accessor.HttpContext.RequestAborted;
  }); 
Respondida el 23/11/2017 a las 19:15
fuente por usuario

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more