【发布时间】:2021-04-15 10:52:22
【问题描述】:
我有从用户那里获取 CancellationToken 的 Web Api,其中的方法(DoWork)也获取 CancellationToken:
[HttpPost]
public async Task<long> GetInfo(CancellationToken cancellationToken)
{
long result = 0;
bool notDone = true;
Task<long> t = Task.Run(async () =>
{
if (cancellationToken.IsCancellationRequested)
cancellationToken.ThrowIfCancellationRequested();
while (notDone && !cancellationToken.IsCancellationRequested)
{
result = await DoWork(cancellationToken);
notDone = false;
}
return result;
}, cancellationToken);
try
{
return await t;
}
catch (AggregateException e)
{
Debug.WriteLine("Exception messages:");
foreach (var ie in e.InnerExceptions)
Debug.WriteLine(" {0}: {1}", ie.GetType().Name, ie.Message);
Debug.WriteLine("\nTask status: {0}", t.Status);
throw;
}
catch (Exception ex)
{
throw;
}
}
private Task<long> DoWork(CancellationToken token)
{
long result = 0;
bool notDone = true;
Task<long> task = Task.Run(() =>
{
if (token.IsCancellationRequested)
token.ThrowIfCancellationRequested();
while (notDone && !token.IsCancellationRequested)
{
Thread.Sleep(8000);
result = 2;
notDone = false;
}
return result;
}, token);
return task;
}
我希望当用户取消请求时,它会中止 DoWork 方法并且不继续该功能,但是在发送异常之后,当“Thread.Sleep”完成时,DoWork 方法会继续。 用户可以像这种方法“cc”一样调用 API 服务,您可以看到它在 5 秒后取消,而在 DoWork 方法中“Thread.Sleep”是 9 秒。用户收到异常,但方法仍在运行。
private async Task<bool> cc()
{
UriBuilder builder = new UriBuilder("http://localhost:12458/api/Test/GetInfo");
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
HttpClient client = new HttpClient();
System.Threading.CancellationTokenSource s = new System.Threading.CancellationTokenSource();
s.CancelAfter(5000);
try
{
var result = client.PostAsJsonAsync<model1>(builder.ToString(), new model1 { }, s.Token).Result;
string tmp = result.Content.ReadAsStringAsync().Result;
long ApiResult = JsonConvert.DeserializeObject<long>(tmp);
}
catch (TaskCanceledException ex)
{
}
catch (OperationCanceledException ex)
{
}
catch (Exception ex)
{
}
finally
{
s.Dispose();
}
return false;
}
【问题讨论】:
-
这段代码是一团糟,它很难帮助,因为有很多可疑的东西正在发生。我的意思是,
notDone有什么意义。这个循环应该在一次迭代后完成,所以我猜它不是你真正的代码。此外,您正在运行假异步(请参阅 stephen cleary)。最后,您试图捕获AggregateException的事实表明您还有其他可疑代码正在运行,您没有显示。 -
让我们退后一步。你想达到什么目的?如果我们知道我们可能能够提供一个简单的工作解决方案。
-
亲爱的@00110001 我希望当用户取消请求时,Web API 服务和其中的方法同时取消,在我的代码“DoWork”中,当用户取消请求时,方法在 Thread.Sleep(8000); 之后继续;
-
好的,如果您无法控制该代码,则没有可靠的方法可以轻松地阻止它。从这里你有 2 个选项,你可以放弃它......这意味着代码仍然会运行,如果它有副作用,那么你不能做太多事情。第二种方法是将此代码加载到一个新的应用程序域中并强制将其删除(这不是最佳的,但它可以比尝试中止当前域中的线程更安全)。
-
不,你不应该在你当前的域中使用
Thread.Abort,唯一相对安全的使用它的方法是加载一个新的AppDomain,在那里运行线程,然后在它没有的地方中止破坏某些东西的机会
标签: c# asp.net-web-api async-await task cancellation-token