2017-01-27 11 views
-1

Я пытаюсь отменить задание задержки async (Task.Delay), которое было создано с помощью запроса веб-api, с другим запросом веб-api, который вызывает отмену. Не похоже, чтобы он отменил таймер для task.delay. Вот фрагмент кода, который я пытаюсь реализовать. Для вашей информации я использую объект Application для хранения объекта CancellationTokenSource для извлечения источника токена по нескольким запросам. Обновление Вопрос: Я ожидаю, что задача будет отменена, выбросив исключение из кода. Но этого никогда не было. Как мне заставить этот код отменить task.delay?Отмена длительной задержки запуска

using Microsoft.Practices.Unity; 
using System; 
using System.Collections.Concurrent; 
using System.Linq; 
using System.Threading; 
using System.Threading.Tasks; 
using System.Web; 
using System.Web.Http; 

namespace WebApplication8.Controllers 
{ 
    public class TaskController : ApiController 
    { 
     [HttpGet] 
     public async Task<string> CreateTask(int id) 
     { 
      var tokenSource = new CancellationTokenSource(); 

      var concurrentTokens = GetConcurrentTokens(); 

      concurrentTokens.TryAdd(id, tokenSource); 

      CancellationToken token = tokenSource.Token; 
      token.ThrowIfCancellationRequested(); 

      await Task.Delay(50000,token); 

      return "Task Created"; 
     } 


     [HttpGet] 
     public async Task<string> Cancel(int id) 
     { 
      var concurrentTokens = GetConcurrentTokens(); 
      CancellationTokenSource item = concurrentTokens.First(t => t.Key == id).Value; 
      item.Cancel(); 
      item.Dispose(); 
      var tokenSource2 = new CancellationTokenSource(); 
      concurrentTokens.TryRemove(id,out tokenSource2); 
      return "Cancelled"; 
     } 

     private ConcurrentDictionary<long, CancellationTokenSource> GetConcurrentTokens() 
     { 
      var tokens = HttpContext.Current.Application["Tokens"]; 

      if (tokens == null) 
      { 
       tokens = new ConcurrentDictionary<long, CancellationTokenSource>(); 
       HttpContext.Current.Application["Tokens"] = tokens; 
      } 

      return (ConcurrentDictionary<long, CancellationTokenSource>) tokens; 
     } 
    } 
} 
+1

«Не похоже, чтобы он отменил таймер для task.delay». -> Можете ли вы подробнее рассказать о том, что видите по сравнению с тем, что вы ожидаете? Я не уверен, в чем проблема. –

+0

Я ожидаю, что исключение должно быть брошено, когда задача отменена. На самом деле я вижу, что задача выполняется непрерывно, не зная, что задача отменена. – Amzath

ответ

2

Я думаю, что отменен, вы можете попробовать его, добавив попробовать поймать так:

try 
    { 
    await Task.Delay(5000, token); 
    } 
    catch(TaskCanceledException ex) 
    { 

    } 

И вы увидите, что он входит в блок поймать, метод не возвращает вещь, потому что TaskCanceledException

+0

Это не сработало. – Amzath

+0

Я тестировал вышеуказанный код с консольным приложением, и он отлично работает –

0

Ваш код выглядит правильно, я проверил это так:

var tc = new TaskController(); 
var backTask1 = tc.CreateTask(1); 
var backTask2 = tc.CreateTask(2); 
// task 2 gets cancelled   
await tc.Cancel(2); 
try 
{ 
    var res2 = await backTask2; 
} 
catch (OperationCanceledException) { } 
// task 1 waits 
await backTask1; 

п .b. что:

  • token.ThrowIfCancellationRequested() ничего не делает, только после того, как вы создали CancellationTokenSource - этот метод буквально бросает исключение, если какой-то код отменил источник уже.
  • Если задача запущена без ожидания, вы не увидите исключений, которые она подняла, пока она не будет ожидаться.
0

Попробуйте использовать TaskCompletionSource. Это работает для меня, но я не уверен, что это то, что вы ищете.

var source = new CancellationTokenSource(); 
var concurrentTokens = GetConcurrentTokens(); 
concurrentTokens.TryAdd(id, source); 
var completionSource = new TaskCompletionSource<object>(); 
source.Token.Register(() => completionSource.TrySetCanceled()); 
var task = Task.Delay(50000, source.Token); 

// Continue when any of these are done. 
await Task.WhenAny(task, completionSource.Task); 
if (task.IsCanceled) 
{ 
    return "Task was not created"; 
} 
return "Task Created"; 

Кроме того, нет необходимости держать Cancelasync. Вы можете вернуть строку вместо Task<string>.

 Смежные вопросы

  • Нет связанных вопросов^_^