如果收到新请求,如何取消上一个任务?

时间:2015-07-03 10:58:11

标签: c# windows-runtime task-parallel-library task dotnet-httpclient

我会尽量简化我的情况,使其更加简洁明了。所以,我正在开发一个 WinRT 应用程序,用户在TextBoxTextChanged事件中输入文本,经过2秒后,我需要提取远程请求来获取基于用户文本的数据。

现在,用户输入文本并初始化了Web请求,但用户立即编写了另一个术语。因此,我需要取消第一个Web请求并启动新请求。

请将以下内容视为我的代码:

private CancellationTokenSource cts;

public HomePageViewModel()
{
    cts = new CancellationTokenSource();
}

private async void SearchPeopleTextChangedHandler(SearchPeopleTextChangedEventArgs e)
{
    //Cancel previous request before making new one        

    //GetMembers() is using simple HttpClient to PostAsync() and get response
    var members = await _myService.GetMembers(someId, cts.Token);

    //other stuff based on members
}

我知道CancellationToken在这里发挥了作用,但我无法弄清楚如何。

2 个答案:

答案 0 :(得分:5)

你已经差不多了。核心思想是单个CancellationTokenSource只能被取消一次,因此必须为每个操作创建一个新的。{/ p>

private CancellationTokenSource cts;

private async void SearchPeopleTextChangedHandler(SearchPeopleTextChangedEventArgs e)
{
  // If there's a previous request, cancel it.
  if (cts != null)
    cts.Cancel();

  // Create a CTS for this request.
  cts = new CancellationTokenSource();

  try
  {
    var members = await _myService.GetMembers(someId, cts.Token);

    //other stuff based on members
  }
  catch (OperationCanceledException)
  {
    // This happens if this operation was cancelled.
  }
}

答案 1 :(得分:0)

我会像这样实现GetMembers方法:

private async Task<List<Member>> GetMembers(int id, CancellationToken token)
    {
        try
        {
            token.ThrowIfCancellationRequested();
            HttpResponseMessage response = null;

            using (HttpClient client = new HttpClient())
            {
                response = await client.PostAsync(new Uri("http://apiendpoint"), content)
                                       .AsTask(token);
            }

            token.ThrowIfCancellationRequested();
            // Parse response and return result
        }
        catch (OperationCanceledException ocex)
        {
            return null;
        }
    }

其余的只是调用cts.Cancel()方法并在每次在处理程序中调用CancellationTokenSource之前创建GetMembers的新实例。当然,正如@Russell Hickey所说,cts应该是全球性的。 (如果有这个类的多个实例,甚至是静态的,并且你总是想在调用这个处理程序时取消GetMembers方法。通常我也有一个包装结果的类,并且有一个额外的属性{{1}将真实的IsSuccessful结果与失败的操作区分开来。