【问题标题】:Avoid returning type Task<Object> from an async function when using HttpClient使用 HttpClient 时避免从异步函数返回类型 Task<Object>
【发布时间】:2016-01-27 21:04:18
【问题描述】:

我正在使用 System.Net.Http.HttpClient 进行 HTTP 调用。看来所有调用都必须是异步的。

假设我的项目结构如下: MVC Web App -> 业务层 -> 数据层

在数据层中,我对 Web API 进行 HTTP 调用以返回数据,最终我使用了这样的函数:

public async Task<IList<Product>> GetProducts()
{
     HttpResponseMessage response = await client.GetAsync("api/products");
     string data = await response.Content.ReadAsStringAsync();
     IList<Product> products = JsonConvert.DeserializeObject<IList<Product>>(data);

     return products;
}

然后进入 BusinessLayer:

public Task<IList<Product>> GetProducts(string name = null)
{
     return _repository.GetProducts(name);
}

最后在MVC控制器中:

public IActionResult Index()
{
    Task<IList<Product>> ProductsTask = _manager.GetProducts();

    IList<Product> ProductsNonTask = products.Result.ToList();

    return View();
}

我真的必须让每个函数都返回一个 Task&lt;IList&lt;Product&gt;&gt; 类型的列表,直到我的 MVC 控制器?正如您在 MVC 控制器中看到的那样,我必须首先检索产品,并将 Task 包裹在它们周围。当我通过它查看产品列表时,调试器看起来有点奇怪。因此,如您所见,我将它们转换为常规产品列表。

我想知道让我的所有函数返回类型 Task&lt;IList&lt;Product&gt;&gt; 一直到我的 MVC 控制器是否是正确的做法,或者是否有解决方法以便我的函数仍然可以返回标准列表的产品,但继续使用 HttpClient 的异步功能?

更新:执行以下操作有什么问题吗:

public IList<Product> GetProducts()
{
     Task<HttpResponseMessage> response = client.GetAsync("api/products");
     if (response.Result.IsSuccessStatusCode)
     {
          string data = response.Result.Content.ReadAsStringAsync().Result;
          IList<Product> products = JsonConvert.DeserializeObject<IList<Product>>(data);

          retVal = products;
     }
}

【问题讨论】:

  • Is there anything wrong with doing the following: 是的,代码无法编译(出于多种不同的原因)。你可以通过简单地编译它来解决这个问题。
  • 我很抱歉我不小心留下了 await 关键字,因为我复制、粘贴和更改了。现在已经修复了。
  • 由于多种不同的原因,代码仍然无法编译。

标签: c# asp.net-mvc asp.net-web-api async-await httpclient


【解决方案1】:

如果您希望操作实际上是异步的,它需要一直是异步的。

在您使用 WaitResult 阻止 Task 的那一刻,它不再是异步的。

所以,不。要么一直使用异步,要么根本不使用它。

我想知道...是否有解决方法让我的函数仍然可以返回标准产品列表但继续使用 HttpClient 的异步功能?

不,真的没有。

您可能应该让您的代码异步,因为它在可扩展性和性能方面有很多好处。但如果您反对这样做,您可以使用具有同步 Web 操作的 WebClient

【讨论】:

  • @BlakeRivell 不要。要么一直使用异步,要么完全避免使用它。不要尝试混合,因为这只会给您带来麻烦。
  • @BlakeRivell 您不必使用await。但您确实需要返回 Task
  • @Servy 我不确定您是否使用过 HttpClient,但它会强制执行异步操作,因为它正在进行网络调用,所以我别无选择。
  • @BlakeRivell 然后不要使用HttpClient。它是专门为提供以前存在的同步 API 的异步对应物而创建的。如果您不想使用异步 API,请不要使用专门创建为异步的 API。
  • @BlakeRivell WebClient 及其 DownloadString(string) 方法。
【解决方案2】:

在我的 MVC 控制器之前,我真的必须让每个函数都返回一个 Task> 类型的列表吗?

是的,您必须这样做,而且您甚至没有捕获所有位置,因为 Index 本身也必须是异步的。

异步确实具有传染性。必要时使用,而不是默认使用。

【讨论】:

  • 我必须在他的情况下使用它,因为我使用的是 HttpClient 吗?
  • HttpClient 强制异步 IO(不幸的是),但如果这对您来说足够好,您可以阻止它。这使您免于“感染”。看这个来决定:stackoverflow.com/a/25087273/122718 为什么 EF 6 教程使用异步调用? stackoverflow.com/a/12796711/122718我们应该切换到默认使用异步 I/O 吗?
  • 阻塞 HttpClient 返回的任务永远不会死锁,顺便说一句。这是安全的,因为 HttpClient 不使用可能已安装的同步上下文。
  • 您能看到我对帖子所做的更新并告诉我这是否是可接受的屏蔽形式吗?
  • 您也可以为此使用 WebClient。它有一个同步 API。 Servy 正确地建议这样做,我也赞同这一点。另一方面,它没有内置 Json 反序列化。不幸的是 HttpClient 强制异步访问。
猜你喜欢
  • 1970-01-01
  • 2019-10-23
  • 1970-01-01
  • 2019-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-09
相关资源
最近更新 更多