C# 如何在WebAPI 2中正确实现异步性

C# 如何在WebAPI 2中正确实现异步性,c#,task-parallel-library,asp.net-web-api,asp.net-web-api2,C#,Task Parallel Library,Asp.net Web Api,Asp.net Web Api2,我在这个问题上看到了一些相互矛盾的信息,我想在这里澄清一下 最初,您会有Web Api操作,例如: Model Action() httpresponsemessageaction() 然后,通过向Web Api添加TPL增强,您可以 Task Action() Task Action() 据推测,ASP.NET足够聪明,可以通过等待任务完成,同时释放接收请求的线程来处理这些任务 漂亮!世界上一切都很简单。但是现在,在Web API 2中,添加了第三种情况IHttpActionResul

我在这个问题上看到了一些相互矛盾的信息,我想在这里澄清一下

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

  • Model Action()
  • httpresponsemessageaction()
然后,通过向Web Api添加TPL增强,您可以

  • Task Action()
  • Task Action()
据推测,ASP.NET足够聪明,可以通过等待任务完成,同时释放接收请求的线程来处理这些任务

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

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

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

说得清楚一点,我确实明白,只要从
IHttpActionResult Action()开始
任务操作()将不会有任何帮助。
ExecuteAsync
的意图是一个难题

世界上一切都很简单。但是现在,在WebAPI2中,添加了
IHttpActionResult

ihttpackationresult
问世的目的是封装
HttpResponseMessage
的生成。这将允许您封装公共逻辑,以便在一组可重用、易于测试的类中创建类似的响应,并将释放控制器操作以处理实际的业务逻辑

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

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

其次,我看到有人建议使用任务,这似乎是完全多余的

如果您的操作使用自然异步操作,您将返回一个
任务。我不认为这是多余的。这是需要的

那么,异步使用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;
   }
}
公共类LogActionResult:IHttpActionResult
{
字符串uri=/**/
公共异步任务ExecuteAsync(CancellationToken CancellationToken)
{
var response=newhttpresponsemessage()
{
内容=新的StringContent(_值),
RequestMessage=\u请求
};
var httpClient=新的httpClient();
等待httpClient.PostAsJsonAsync(uri,响应);
返回响应;
}
}

异步记录并返回
HttpResponseMessage
。如果您没有异步操作,
Task.FromResult
将非常好。

我不喜欢在不同版本之间实现供应商接口的方式,有更准确的版本:

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

        return Ok();
    }
}

使用
Task.FromResult
是一个实现细节,也就是说,实现者已经决定不使用异步性,但如果有保证的话,将来可能会决定使用异步性。然而,没有异步实现同步API的好方法。那么,在实践中,人们会在真实场景中创建IHttpActionResult的实现吗?