DelegatingHandler 在返回 Task<HttpResponseMessage> 时挂起

DelegatingHandler hangs when returning Task<HttpResponseMessage>

这是我非常简单的 class 演示问题:

public class SimpleHandler : DelegatingHandler
    {
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            return new Task<HttpResponseMessage>(
                        () => new HttpResponseMessage(HttpStatusCode.Unauthorized));

            //return base.SendAsync(request, cancellationToken);
        }
    }

预期的行为是 401 响应。如果我调试它,执行到达 return 语句并在我按下 F5 时继续,但 http 请求永远不会 returns 并且 http 客户端最终会等待超时。

我真的很困惑,因为我正在做编译器告诉我的事情:return a Task<HttpResponseMessage>。对 base.SendAsync 的调用工作得很好。我在这里错过了什么?

编辑:

好的,所以我发现

return Task.FromResult(new HttpResponseMessage(HttpStatusCode.Unauthorized));

按预期工作。但是,我想了解为什么上述方法失败了?在这两种情况下,我都在创建一个 Task<HttpResponseMessage> 为什么我只在第二种情况下得到预期的行为?

您可以使用静态 Task.FromResult 方法来创建一个 Task,它是一个特定值的包装器:

Task.FromResult<HttpResponseMessage>(new HttpResponseMessage(HttpStatusCode.Unauthorized));

区别很大。使用构造函数创建的任务表示尚未 运行 的任务,因此还没有结果集。在您的情况下,无需完成任何工作,因此无需创建和 运行 任务。否则 You should use Task.Run instead of a constructor

并且由于您只在示例中创建了任务,而没有调用 Start(),它将具有 Created 状态并且永远不会自行完成,因为它不会启动。因此您的进程挂起,因为在管道的更下方,系统将等待任务完成。

第二个Task,使用FromResult创建,代表一个Task已经完成,结果为设定值。

检查两个任务的 de Status 属性 并注意差异。 (创建与 RanToCompletion)

由于您没有实际工作要做,因此您应该坚持使用 FromResult