Прервать AJAX-запрос через CancellationToken в ASP.NET MVC - PullRequest
0 голосов
/ 31 мая 2018

У меня есть приложение ASP.NET MVC, которое взаимодействует с внешними ресурсами, и есть операция, которая занимает много времени.Так что в контроллере у меня есть метод, подобный этому

[HttpPost]
public async Task<JsonResult> SomeMethod(..., CancellationToken token)
{
    await _someService.ExecuteSlowOperationAsync(..., token);
    ...
}

И эта медленная операция выглядит как

public async Task ExecuteSlowOperationAsync(..., CancellationToken token)
{
    return await Task.Run(() => 
    {
       //interacting with external resource
    }, token);
} 

Этот метод связан с модальным представлением, и если запрос займет так много времени, пользователь может решитьзакрой его.В соответствии с этим я должен отменить запрос, не ожидая результатов, поэтому на стороне клиента у меня есть код вроде

...
var request = $.ajax(...);

...

$('#modal').on('hidden.bs.modal', function () {
  request.abort();
});

Если я правильно понял article , токен отмены связывается с запросом через frameworkмодель связующего и не нужно что-то с ней делать.Когда пользователь закрывает модальную форму, в браузере консоли я вижу, что запрос получает статус «отменен», но на стороне сервера медленная работа все еще выполняется.Также я попробовал с

CancellationToken disconnectedToken = Response.ClientDisconnectedToken;            
var source = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, disconnectedToken);

, а затем взял токен из этого источника, но все равно ничего не получил.

Я чувствую, что упускаю какую-то важную вещь и неправильно понимаю эту ситуацию.Есть идеи, как заставить это работать?

1 Ответ

0 голосов
/ 07 июня 2019

Я, наверное, немного опоздал с ответом.Но я думаю, что нашел твою проблему.Использование Task.Run(Action action, CancellationToken cancellationToken) для отмены длительной операции может не всегда работать.

Использование CancellationToken для тайм-аута в Task.Run не работает

Если длительная операцияв своем собственном коде вы должны написать что-то вроде этого

public async Task ExecuteSlowOperationAsync(..., CancellationToken token)
{
    while (true)
    {
        if(cancelToken.IsCancellationRequested)
        {
            return;
        }
        ...
    }
}

Если вы не можете изменить исходный код самой длительной операции, вы можете использовать WithCancellation из Microsoft.VisualStudio.Threading.ThreadingTools (см. https://stackoverflow.com/a/33396646/9483821 для получения дополнительной информации), который вы даже могли использовать ранее на своем контроллере

[HttpPost]
public async Task<JsonResult> SomeMethod(..., CancellationToken token)
{
     CancellationToken disconnectedToken = Response.ClientDisconnectedToken;            
     var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, disconnectedToken).Token;
     await _someService.ExecuteSlowOperationAsync(...).WithCancellation(linkedToken);
     ...
}
...