如何取消异步任务?

时间:2015-04-15 09:14:25

标签: c# async-await asp.net-web-api2

我有一个加载数据的方法,例如:

public async GetCustomers()
{
    await Task.Run(() => {
        for (int i = 0; i < 99; i++)
            customers = customerRequest.GetCustomers();
    });
}

customerRequest是一个使用HttpClient连接到WebApi服务器的简单类。调用堆栈如下:

  

method-&gt; request-&gt; controller action-&gt; server layer-&gt; repository-&gt; db

目前,控制器操作返回IHttpActionResult,而服务和存储库层返回IEnumerable<Customer>。所有方法都是同步调用的。

出于测试目的,我添加了for循环以增加任务的延迟并查看正在执行的SQL语句。

如果用户决定关闭表单,则任务仍在后台执行,SQL语句仍然会发送到数据库。

取消此类任务的正确方法是什么?

2 个答案:

答案 0 :(得分:2)

您要使用CancellationTokenSource,并将其CancellationToken传递给您的方法。表单关闭后,请致电CancellationTokenSource.Cancel

但是,请注意,您希望将CancellationToken传递给实际使用它的方法。正如我在博客中描述的那样Task.Run is not one of them

您真正想要做的是从最低级别(在客户端)开始,并将CancellationToken传递给您正在使用的任何HttpClient方法(即like this one })。

然后继续前进。我还建议让你的代码异步。当你完成后,你应该得到GetCustomers,如下所示:

public async Task GetCustomersAsync(CancellationToken token)
{
  for (int i = 0; i < 99; i++)
    customers = await customerRequest.GetCustomersAsync(token);
}

如果您真的确定(tm)没有虚假请求消失,您还可以在执行请求之前明确检查令牌:

public async Task GetCustomersAsync(CancellationToken token)
{
  for (int i = 0; i < 99; i++)
  {
    token.ThrowIfCancellationRequested();
    customers = await customerRequest.GetCustomersAsync(token);
  }
}

如果这对你很重要,你也可以handle cancellation on the server side

答案 1 :(得分:1)

Checkout CancellationTokenSource。您可以保留其中一个长寿命按钮或关闭事件调用取消()。如果您希望取消所有任务,只需将其传递给您的所有任务。该任务将抛出异常,因此请确保包装try catch。您还可以检查您的任务中是否已取消取消请求以尝试以优雅的方式突破。

var cts = new CancellationTokenSource();

await Task.Run(() =>
{
    //do work, will throw if cts.Cancel() is called
}, cts.Token);

//wait 2 seconds then cancel
await Task.Delay(2000);

cts.Cancel();