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