ASP.NET Web API + длительная отмена операции - PullRequest
11 голосов
/ 19 марта 2012

Есть ли способ выяснить в бета-версии ASP.NET Web API, был ли отменен HTTP-запрос (отменен пользователем по какой-либо другой причине)? Я ищу возможность получить своего рода токен отмены из коробки, который будет сигнализировать о том, что запрос отменен, и поэтому длительные операции также должны быть прерваны.

Возможный связанный вопрос - вариант использования для класса CancellationTokenModelBinder. В чем причина наличия отдельного связующего для токена отмены?

Ответы [ 3 ]

8 голосов
/ 19 марта 2012

Я бы хотел немного подвести итог.Единственный подход, который, кажется, работает, это проверка Response.IsClientConnected.Вот некоторые технические детали относительно того, что происходит за сценой: здесь и здесь Этот подход имеет некоторые недостатки:

  • Работает только под IIS (безхостинг, нет Dev-сервера);
  • Согласно некоторым SO ответы могут быть медленными (не реагировать сразу после отключения клиента): здесь ;
  • Есть соображения относительно этогостоимость звонка: здесь

В конце я придумал следующий фрагмент кода для внедрения CancellationToken на основе IsClientConnected в контроллер Web API:

    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);
    }
}
8 голосов
/ 19 марта 2012

Время от времени вы можете проверять Response.IsClientConnected, чтобы убедиться, что браузер все еще подключен к серверу.

0 голосов
/ 24 ноября 2017

Если вы добавили CancellationToken в методы контроллера, он будет автоматически добавлен платформой, и когда клиент вызовет xhr.abort (), токен будет автоматически отменен

Что-то похожее на

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

Для MVC вы также можете обратиться к

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

Для .NetCore

services.AddTransient<ICustomInterface>(provider => { 
     var accessor = provider.GetService<IHttpContextAccessor>);
     accessor.HttpContext.RequestAborted;
  }); 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...