C# 如何使用Continuation正确取消第三方物流任务
我有一个长时间运行的操作,我正在使用TPL将其放在后台线程上。我目前所做的工作很有效,但我对在取消请求期间应该在哪里处理我的C# 如何使用Continuation正确取消第三方物流任务,c#,task-parallel-library,continuations,cancellation,request-cancelling,C#,Task Parallel Library,Continuations,Cancellation,Request Cancelling,我有一个长时间运行的操作,我正在使用TPL将其放在后台线程上。我目前所做的工作很有效,但我对在取消请求期间应该在哪里处理我的聚合异常感到困惑 在按钮单击事件中,我启动流程: private void button1_Click(object sender, EventArgs e) { Utils.ShowWaitCursor(); buttonCancel.Enabled = buttonCancel.Visible = true; try {
聚合异常
感到困惑
在按钮单击事件中,我启动流程:
private void button1_Click(object sender, EventArgs e)
{
Utils.ShowWaitCursor();
buttonCancel.Enabled = buttonCancel.Visible = true;
try
{
// Thread cancellation.
cancelSource = new CancellationTokenSource();
token = cancelSource.Token;
// Get the database names.
string strDbA = textBox1.Text;
string strDbB = textBox2.Text;
// Start duplication on seperate thread.
asyncDupSqlProcs =
new Task<bool>(state =>
UtilsDB.DuplicateSqlProcsFrom(token, mainForm.mainConnection, strDbA, strDbB),
"Duplicating SQL Proceedures");
asyncDupSqlProcs.Start();
//TaskScheduler uiThread = TaskScheduler.FromCurrentSynchronizationContext();
asyncDupSqlProcs.ContinueWith(task =>
{
switch (task.Status)
{
// Handle any exceptions to prevent UnobservedTaskException.
case TaskStatus.Faulted:
Utils.ShowDefaultCursor();
break;
case TaskStatus.RanToCompletion:
if (asyncDupSqlProcs.Result)
{
Utils.ShowDefaultCursor();
Utils.InfoMsg(String.Format(
"SQL stored procedures and functions successfully copied from '{0}' to '{1}'.",
strDbA, strDbB));
}
break;
case TaskStatus.Canceled:
Utils.ShowDefaultCursor();
Utils.InfoMsg("Copy cancelled at users request.");
break;
default:
Utils.ShowDefaultCursor();
break;
}
}, TaskScheduler.FromCurrentSynchronizationContext()); // Or uiThread.
return;
}
catch (Exception)
{
// Do stuff...
}
}
在按钮单击事件中(或使用委托
(buttonCancel.Click+=委托{/Cancel the Task/}),我按如下方式取消
任务`:
private void buttonCancel_Click(object sender, EventArgs e)
{
try
{
cancelSource.Cancel();
asyncDupSqlProcs.Wait();
}
catch (AggregateException aggEx)
{
if (aggEx.InnerException is OperationCanceledException)
Utils.InfoMsg("Copy cancelled at users request.");
}
}
这将捕获方法DuplicateSqlProcsFrom
中的OperationCanceledException
fine并打印我的消息,但是在asyncDupSqlProcs.ContinueWith(task=>{…})提供的回调中;
任务上方的状态始终是RanToCompletion
,应该取消它
在本例中,捕获和处理Cancel()
任务的正确方法是什么。我知道在中和中所示的简单案例中如何执行此操作,但在本例中,当运行延续时,我感到困惑
在这种情况下,我如何捕获取消任务,以及如何确保任务状态得到正确处理?Sacha Barber有大量关于TPL的文章。试试看,他用continuation和canceling描述了简单的任务。您正在捕获Duplicate SQLProcsFrom中的OperationCanceledException
方法,该方法防止其任务
看到它,并相应地将其状态设置为已取消
。由于已处理异常,DuplicateSqlProcsFrom
完成而不引发任何异常,其相应的任务在RanToCompletion
状态下完成
DuplicateSqlProcsFrom
不应捕获OperationCanceledException
或AggregateException
,除非它正在等待自己的子任务。引发的任何异常(包括OperationCanceledException
)应保持未捕获状态以传播到延续任务。在延续的开关
语句中,应检查故障
案例中的任务。异常
,并在适当的案例中处理取消
在后续lambda中,任务.Exception
将是一个聚合异常
,它有一些简便的方法来确定错误的根本原因,并对其进行处理。请特别检查内部异常
(注意“S”),GetBaseException
,flant
和Handle
成员
编辑:在获得故障
的任务状态
而不是已取消时
在构造asyncDupSqlProcs
任务的行上,使用一个task
构造函数,该构造函数接受来自delegate的DuplicateSqlProcsf和将令牌与任务关联的CancellationToken
当您在DuplicateSqlProcsFrom
中的令牌上调用ThrowIfCancellationRequested
时,抛出的OperationCanceledException
包含对已取消令牌的引用。当任务捕获异常时,它会将该引用与与其关联的CancellationToken
进行比较。如果它们匹配,然后任务转换到已取消
。如果它们不匹配,则任务基础结构已编写为假设这是一个不可预见的错误,而任务转换到故障
虽然这在理论上可以回答这个问题,但在这里包括答案的基本部分,并提供链接供参考。这是我提供的链接。虽然他涵盖了任务取消,但这不在我这里的更复杂的场景中-因此对我没有用。谢谢你的时间。谢谢你。这真的很有帮助ped.我已经到了从DuplicateSqlProcsFrom
方法中删除Handling的阶段,但仍在尝试在其他地方捕获它。我已经按照您的建议做了,但在我的继续方法中,我只得到了TaskStatus.Faulted
条件,从未TaskStatus.Cancelled
。您知道为什么会这样吗?我想e在答案中添加了对这种行为的解释和解决方案。
private void buttonCancel_Click(object sender, EventArgs e)
{
try
{
cancelSource.Cancel();
asyncDupSqlProcs.Wait();
}
catch (AggregateException aggEx)
{
if (aggEx.InnerException is OperationCanceledException)
Utils.InfoMsg("Copy cancelled at users request.");
}
}