【问题标题】:How to properly implement asynchronicity in web api 2如何在 web api 2 中正确实现异步
【发布时间】:2015-05-15 19:01:11
【问题描述】:

我一直看到有关该主题的一些相互矛盾的信息,我想在这里澄清一下。

最初,您将拥有 Web Api 操作,例如:

  • Model Action();
  • HttpResponseMessage Action();

然后,通过向 Web Api 添加 TPL 增强功能,您可以拥有

  • Task<Model> Action();
  • Task<HttpResponseMessage> Action();

据推测,ASP.NET 将足够聪明,可以通过等待任务完成并同时释放接收请求的线程来处理这些问题。

美丽! 世界上一切都很简单。但是现在,在 Web API 2 中,增加了IHttpActionResult,第三种情况,它提供了Task<HttpResponseMessage> ExecuteAsync() 方法。

首先,如果您检查IHttpActionResult 的实现,您会看到每个ExecuteAsync 实际上只返回Task.FromResult(根本不是异步的,而且看起来它不会比同步返回@987654331 带来任何性能提升@)。其次,我看到有人推荐使用Task<IHttpActionResult>,这似乎完全是多余的。我什至看到有少数人建议您将这些方法结合起来并从您的操作中返回Task.Factory.StartNew(..),这似乎有点荒谬。

那么异步使用IHttpActionResult的正确方法是什么?您是简单地实现自己的,并在那里执行异步操作†,还是返回Task<IHttpActionResult>,使您的方法async,并在调用return Ok()(或等效)之前等待IO绑定操作?

需要明确的是,我很清楚,简单地从 IHttpActionResult Action();Task<IHttpActionResult> Action(); 而不更改方法主体将无济于事。 ExecuteAsync 的意图是一个谜。

https://stackoverflow.com/a/21609402/661422

【问题讨论】:

  • 使用Task.FromResult 是一个实现细节——也就是说,实现者已经决定不使用异步,但如果有必要,将来可能会决定使用它。而没有很好的方法来异步实现同步 API。

标签: c# task-parallel-library asp.net-web-api asp.net-web-api2


【解决方案1】:

世界上的一切都很简单。但是现在,在 Web API 2 中,增加了 IHttpActionResult

IHttpActionResult来到这个世界,就是为了封装HttpResponseMessage的生成。这将允许您将用于在一组类中创建类似响应的通用逻辑封装起来,这些类可以重用、易于测试,并且可以释放控制器操作来处理实际的业务逻辑。

首先,如果您检查 IHttpActionResult 的实现,您会发现每个 ExecuteAsync 实际上只返回 Task.FromResult

我假设会发生这种情况,例如,NotFound();Ok() 扩展方法只返回构造的 HttpResponseMessage,仅此而已。也许您还没有遇到过需要这样做的现实世界场景。

其次,我看到有人推荐使用 Task,这似乎完全多余。

如果您的操作使用自然异步操作,您将返回 Task<IHttpActionResult>。我不明白这怎么可能是多余的。它是必需的。

那么异步使用 IHttpActionResult 的正确方法是什么?

正确的方法与所有异步方法相同。假设您想在返回到通过 HTTP 端点公开异步 API 的第 3 方日志框架之前记录每个响应,您可以这样做:

public class LogActionResult : IHttpActionResult
{
   string uri = /* ... */

   public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
   {
       var response = new HttpResponseMessage()
       {
           Content = new StringContent(_value),
           RequestMessage = _request
       };

       var httpClient = new HttpClient();
       await httpClient.PostAsJsonAsync(uri, response);

       return response;
   }
}

异步记录并返回HttpResponseMessage。如果你没有异步操作,Task.FromResult 会很好。

【讨论】:

  • 那么,在实践中,人们会继续在现实世界的场景中创建 IHttpActionResult 的实现吗?
【解决方案2】:

我不喜欢我需要实现从一个版本到另一个版本的供应商接口的方式,有更准确的版本:

public class FibonacciController : ApiController
{
    public IHttpActionResult Get(int fibN)
    {
        Task.Factory.StartNew(() =>
        {
            var fibNResult = FibonacciHelpers.CalculateFibonacci(fibN);
        });

        return Ok();
    }
}

【讨论】:

    猜你喜欢
    • 2018-02-13
    • 1970-01-01
    • 2018-11-12
    • 2014-01-25
    • 1970-01-01
    • 2018-07-26
    • 1970-01-01
    • 1970-01-01
    • 2014-11-16
    相关资源
    最近更新 更多