所以我启动了一个HttpListener
来等待OAuth2
的响应,在理想的情况下,它只会在用户登录浏览器时存在几秒钟,然后我们会收到令牌。
我还希望这有一个CancellationToken
,以便用户可以停止收听后,延迟,如果他们希望这样做。
我最初的想法是使用沿着以下的东西:
_listener.Start();
Task<HttpListenerContext> t = _listener.GetContextAsync();
while (!cancelled.IsCancellationRequested)
{
if (t.IsCompleted)
{
break;
}
await Task.Run(() => Thread.Sleep(100));
}
HttpListenerContext ctx = t.Result;
//...
_listener.Stop();
但这并不适合我,原因有很多(奇怪的async
用法、轮询等)。
所以我想我可以将同步版本_listener.GetContext()
与Task.Run(func<T>, CancellationToken)
结合使用:
_listener.Start()
HttpListenerContext ctx = await Task.Run(() => _listener.GetContext(), cancelled);
//...
_listener.Stop();
这稍微好一点,代码至少更整洁了,尽管使用方法的同步版本与Task
异步似乎有些笨拙...
然而,这并不像我所期望的那样(当令牌被取消时中止正在运行的任务)。
这让我觉得这应该是一件很简单的事情,所以我想我错过了什么。
因此我的问题是...如何以可取消的方式异步侦听HttpListener
?
4条答案
按热度按时间r55awzrz1#
因为
GetContextAsync
方法不支持取消,这基本上意味着您不可能取消实际的IO操作,也不可能取消该方法返回的Task
,除非您使用Abort
或Stop
HttpListener
。因此,这里的主要焦点始终是将控制流返回到代码的 hack。虽然@guru-stron和@peter-csala的答案应该都能解决问题,但我只是想分享另一种不必使用
Task.WhenAny
的方法。您可以使用
TaskCompletionSource
来 Package 任务,如下所示:并按如下方式传递控件:
czfnxgou2#
在net Core / Net 6中,您可以通过WaitAsync()方法设置cancellationToken和/或超时。
它将在取消和/或超时时引发异常。
示例:
wwtsj6pe3#
我建议创建可取消的无限任务(例如
Task.Delay(Timeout.Infinite, token)
)并使用Task.WhenAny
。zzoitvuj4#
这里还有另一个解决方案:
因为我们不能等待
CancellationToken
,这就是为什么必须应用以下技巧CancellationToken
确实公开了一个Register
方法,我们可以在其中定义一个回调函数,每当发生取消操作时都会调用该函数await
该任务为了创建一个
Task
,它被设置为在取消发生时完成,我使用了TaskCompletionSource
,你也可以使用SemaphoreSlim
或任何其他有异步等待的信令对象,比如AsyncManualResetEvent
。cancellationSignal
作为state
参数传递给Register
TrySetResult
Task.WhenAny
Task
Task
是抵消,那么我们可以break
/return
/throw
...Task
就是contextTask
,则我们可以继续正常流程