HttpRequest не прерывается (отменяется) при прерывании работы браузера в ASP.NET Core MVC

Я написал следующий контроллер MVC для проверки функциональности отмены:

class MyController : Controller
{
    [HttpGet("api/CancelTest")]
    async Task<IActionResult> Get()
    {
        await Task.Delay(1000);
        CancellationToken token = HttpContext.RequestAborted;
        bool cancelled = token.IsCancellationRequested;
        logger.LogDebug(cancelled.ToString());
        return Ok();
    }
}

Скажем, я хочу отменить запрос, поэтому значение «true» регистрируется в действии контроллера выше. Это возможно на стороне сервера, если сервер реализует IHttpRequestLifetimeFeature. К счастью, Kestrel умеет, и это можно сделать следующим образом:

var feature = (IHttpRequestLifetimeFeature) HttpContext.Features[typeof(IHttpRequestLifetimeFeature)];
feature.Abort();

Однако проблема в том, что я хочу отменить запрос на стороне клиента. Например, в браузере. В предварительных версиях ASP.NET MVC / WebApi токен отмены будет автоматически отменен, если браузер прервал запрос. Пример: обновите страницу пару раз в Chrome. На вкладке «Сеть» инструментов Chrome dev вы можете увидеть, что предыдущий (незавершенный) запрос был отменен.

Дело в том, что в ASP.NET Core, запущенном на Kestrel, я вижу в журнале только следующую запись:

Microsoft.AspNetCore.Server.Kestrel.Internal.Networking.UvException: ошибка -4081 Операция ECANCELED отменена

Таким образом, запрос на прерывание от браузера ДЕЙСТВИТЕЛЬНО поступает и обрабатывается веб-сервером Kestrel. Однако это не влияет на свойство RequestAborted HttpContext в контроллере, поскольку значение «false» по-прежнему регистрируется методом.

Вопрос: Есть ли способ прервать / отменить метод моего контроллера, чтобы свойство HttpContext.RequestAborted было помечено как отмененное?

Возможно, я смогу сделать что-то, что подписалось бы на триггер отмены операции Kestrel и вызвало бы метод IHttpRequestLifetimeFeature.Abort ()?

Обновление: я провел дополнительное тестирование, и кажется, что HttpRequest IS фактически прерван, но, похоже, есть какая-то задержка до того, как отмена действительно произойдет. Задержка не учитывается по времени и, похоже, исходит прямо из libuv (библиотеки, на которой построен веб-сервер Kestrel). Я разместил дополнительную информацию на https://github.com/aspnet/KestrelHttpServer/issues/1103

Дополнительные обновления: проблема была перемещена в другую, так как предыдущая содержала несколько проблем. https://github.com/aspnet/KestrelHttpServer/issues/1139


person Nicky Muller    schedule 19.09.2016    source источник
comment
Я голосую за то, чтобы закрыть этот вопрос как не по теме, потому что проблема, похоже, уже решена   -  person Set    schedule 20.06.2017
comment
@ Set: Это нормально. Это действительно должно быть исправлено в версии 2.0. Я не могу закрыть вопрос сам, а?   -  person Nicky Muller    schedule 20.06.2017
comment
вы можете удалить вопрос, если считаете, что он больше не полезен для других пользователей, или вы можете опубликовать собственный ответ (и принять его позже) и сказать, что это была ошибка в реализации Kestrel Server, которая теперь исправлена.   -  person Set    schedule 20.06.2017
comment
При использовании IIS в качестве обратного прокси-сервера для Kestrel github.com/aspnet/AspNetCoreModule/issues/38. Таким образом, несмотря на то, что исходная проблема была исправлена, это все еще очень информативный вопрос.   -  person Nenad    schedule 27.09.2018


Ответы (1)


Оказывается, простое использование HttpContext.RequestAborted действительно является правильным способом, но из-за ошибки в Kestrel (порядок, в котором обрабатывались пакеты FIN / RST), запрос не был прерван при прерывании работы браузера.

Наконец, ошибка должна быть исправлена ​​в Kestrel 2.0.

Смотрите обновления в моем вопросе для получения дополнительной информации.

person Nicky Muller    schedule 20.06.2017
comment
Спасибо. Да ты прав. Возможно, в Kestrel есть ошибка. Я пробовал использовать HttpContext.RequestAborted, но все равно это не сработало, поэтому я попытался не использовать IIS Express (см. stackoverflow.com/questions/47153525/), и это сработало. - person Advait Baxi; 02.09.2019