ASP.NET Web API + отмена длительных операций
Есть ли способ выяснить в ASP.NET Web API beta был ли HTTP-запрос отменен (прерван пользователем по какой-либо другой причине)? Я ищу возможность иметь своего рода маркер отмены из коробки, который будет сигнализировать, что запрос прерван, и поэтому долгосрочные операции также должны быть прерваны.
Возможный связанный вопрос-вариант использования класса CancellationTokenModelBinder. Какая причина иметь отдельную привязку для токена отмены?
3 ответов:
Я хотел бы подвести некоторые итоги. Единственный подход, который, кажется, работает, - это проверка ответа.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); } }
Если вы добавили 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; });
Comments