如何在Web API 2中正确地实现异步性

5
我看到了一些关于这个主题的矛盾信息,我想在这里澄清一下。最初,您可能会有Web Api操作,例如:
Model Action();
HttpResponseMessage Action();
然后,通过对Web Api的TPL增强,您可以拥有
Task Action();
Task Action();
据说,ASP.NET足够聪明,可以通过等待任务完成并在此期间释放拾取请求的线程来处理它们。
太好了!世界上的一切都很简单。但是现在,随着Web API 2的推出,有第三种情况,即添加了IHttpActionResult,它提供Task ExecuteAsync()方法。
首先,如果您检查IHttpActionResult的实现,您会发现每个ExecuteAsync实际上只返回Task.FromResult(完全不是异步的,并且似乎不会比同步返回HttpResponseMessage带来任何性能提升)。其次,我看到人们建议使用Task<IHttpActionResult>,这似乎完全是多余的。我甚至看到一些人建议将这些方法结合起来并从您的操作中返回Task.Factory.StartNew(..),这似乎有点荒谬。

那么正确的异步使用IHttpActionResult的方式是什么?您只需实现自己的异步操作,或者返回Task<IHttpActionResult>,使您的方法成为async,并在调用return Ok()(或等效操作)之前等待IO-bound操作即可。

需要明确的是,我显然理解,仅仅从IHttpActionResult Action();转换为Task<IHttpActionResult> Action();而不改变方法体将不会有任何帮助。这是一个谜题的ExecuteAsync的意图。

https://dev59.com/IGEi5IYBdhLWcg3wMZ3a#21609402

->

† {{链接1:https://dev59.com/IGEi5IYBdhLWcg3wMZ3a#21609402}}


您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Jean Hominal
2个回答

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 就可以完美地解决问题。


那么,在实践中,人们是否会在真实世界的场景中创建IHttpActionResult的实现呢? - Kir

0

我不喜欢需要实现供应商接口的方式,因为这些接口在不同版本中会发生变化,有更准确的版本:

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

        return Ok();
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接