从 Web API 同步调用外部 api

Posted

技术标签:

【中文标题】从 Web API 同步调用外部 api【英文标题】:Call external api from Web API synchronously 【发布时间】:2015-02-16 22:30:08 【问题描述】:

我需要从我的 Web API 2 控制器调用外部 api,类似于这里的要求:

Calling external HTTP service using HttpClient from a Web API Action

但是,上面的解决方案需要在我的 api 方法的 GET 调用中添加 async 关键字,从而使我的调用异步。我更喜欢使用同步方法向我的 API 的客户端呈现,但仍然能够从我自己的调用外部 api(并且需要在我的 api 返回之前返回)。有没有办法做到这一点?

【问题讨论】:

【参考方案1】:

阻止async 操作可能很危险。它会损害性能并可能导致死锁(更多内容请参见 Should I expose synchronous wrappers for asynchronous methods?)

但是,如果您确定这是您想要做的,IMO 最好使用GetAwaiter().GetResult()

using (HttpClient httpClient = new HttpClient())

    var response = httpClient.GetAsync(_endpoint).GetAwaiter().GetResult();
    var result = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
    // Do stuff...

无论是Task 还是Task<T>,都是一样的,await 转换为相同的调用(尽管await 任务已经完成)并且Task.Result(或Task.Wait)包含任何异常在AggregateException 中,而GetAwaiter().GetResult() 只抛出第一个Exception,就像await 一样。

【讨论】:

感谢您的提醒...经过进一步研究后,我确定最好让客户端决定是否异步调用 api。我还发现这篇文章更简洁地解释了这个问题:blog.stephencleary.com/2012/07/dont-block-on-async-code.html

以上是关于从 Web API 同步调用外部 api的主要内容,如果未能解决你的问题,请参考以下文章

使用 Celery 通过 Gevent 进行实时、同步的外部 API 查询

Web API 2 - 阻止所有外部调用

通过 Web API 操作使用 HttpClient 调用外部 HTTP 服务

如何调用外部的Web API

保护 Web api 不被浏览器外部调用

从 laravel 调用 HTTPS 请求到外部 API