IHttpActionResult.ExecuteAsync() 重载返回的任务不是 运行

task returned by IHttpActionResult.ExecuteAsync() overload is not run

我正在尝试创建一个自托管 Web 服务,该服务以 Microsoft.Owin.Hosting.WebApp.Start<NotifyStartup>("http://localhost:9000/") 启动其服务器并包含一个派生自 System.Net.Http.ApiController 的控制器。 NotifyStartup 看起来像这样:

using System.Web.Http;
using Owin;
...
class NotifyStartup
{
    public void Configuration(IAppBuilder appBuilder)
    {
        var config = new HttpConfiguration();
        config.MapHttpAttributeRoutes();

        appBuilder.UseWebApi(config);
    }
}

控制器有这个 URI 处理程序:

using System.Web.Http;
...
[Route("notify")]
[HttpPost]
public IHttpActionResult Notify([FromBody]object body)
{
    return new HttpAction();
}

这是 HttpAction:

using System.Net.Http;
using System.Web.Http;
using System.Threading;
using System.Threading.Tasks;
...
public class HttpAction : IHttpActionResult
{
    public HttpAction() { }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        return new Task<HttpResponseMessage>(() =>
        {
            var rspContent = "here's a response string";
            var rsp = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
            if (!string.IsNullOrEmpty(rspContent))
            {
                rsp.Content = new StringContent(rspContent);
            }
            return rsp;
        }, cancellationToken);
    }
}

(在某些时候 HttpAction 会注意 Notify()body 参数并且 rspContent 会被分配一些需要一些数据库查找的东西,这就是为什么我我正在尝试让这项工作异步进行。)

当我 运行 程序和 POST 到 http://localhost:9000/notify/ 调用 URI 处理程序时,它会创建一个 HttpAction 实例和该实例的 ExecuteAsync() 方法叫做。但是,它 returns 的任务永远不会 运行,并且客户端会挂起等待响应。如果我更改 ExecuteAsync() 以便同步完成工作并在包装器任务中返回响应:

var rspContent = "here's a response string";
var rsp = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
if (!string.IsNullOrEmpty(rspContent))
{
    rsp.Content = new StringContent(rspContent);
}
return Task.FromResult(rsp);

包装器任务 运行 并且客户端收到其响应。

据我所知,new Task<>...Task.FromResult() 创建的任务看起来应该与调用者相同。为什么它会 await (或者它为获得结果而实际做的任何事情)一个而不是另一个?我究竟做错了什么?有可能使这项工作吗?

the tasks created by new Task<> and Task.FromResult() should look identical to the caller.

从调用者的角度来看,它们看起来确实相同,但从实现的角度来看,它们并不相同。

Task 构造函数不会启动任务,这就是您不应该使用它的原因。而是使用 Task.Run 其中 returns 一个热门任务:

public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
    return Task.Run(() =>
    {
        var rspContent = "here's a response string";
        var rsp = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
        if (!string.IsNullOrEmpty(rspContent))
        {
            rsp.Content = new StringContent(rspContent);
        }
        return rsp;
    }, cancellationToken);
}

虽然我认为这本身可能是多余的,因为 WebAPI 中的操作本身已经 运行 在线程池线程上,将它包装在一个额外的线程中通常是多余的.