如何在web api中正确实现异步性2

时间:2015-05-15 19:01:12

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

我一直在看到关于这个主题的一些相互矛盾的信息,我想在此澄清一些。

最初,您将拥有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实际上只返回{​​{1}}(根本不是异步,并且似乎不会给出任何性能获得同步返回Task.FromResult)。其次,我看到人们建议使用HttpResponseMessage,这似乎完全是多余的。我甚至看到一些人建议你将这些方法结合起来并从你的行动中返回Task<IHttpActionResult>,这似乎有些荒谬。

那么异步使用Task.Factory.StartNew(..)的正确方法是什么?你只是实现自己的,并在那里进行异步操作†,或者你是否返回IHttpActionResult,制作你的方法Task<IHttpActionResult>,并在调用async之前等待IO绑定操作(或者当量)?

要明确的是,我明显明白,只需从return Ok()转到IHttpActionResult Action();而不更改方法正文就无济于事。 Task<IHttpActionResult> Action();的目的是谜题。

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

2 个答案:

答案 0 :(得分:3)

  

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

为了封装IHttpActionResult的生成,

HttpResponseMessage来到世界各地。这将允许您封装通用逻辑,以便在一组类中创建类似的响应,这些类可以重用,轻松测试,并且可以释放控制器操作来处理实际的业务逻辑。

  

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

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

  

其次,我看到人们建议使用Task,这似乎完全是多余的。

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

  

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

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

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就完全可以了。

答案 1 :(得分:0)

我不喜欢我需要实现从版本更改为版本的供应商界面的方式,有更准确的版本:

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

        return Ok();
    }
}