我有一个加载数据的方法,例如:
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语句仍然会发送到数据库。
取消此类任务的正确方法是什么?
答案 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();