【问题标题】:Calling API inside foreach loop in c#在 C# 中的 foreach 循环内调用 API
【发布时间】:2021-02-28 16:08:49
【问题描述】:

我有以下调用我的 API 的函数

private async void applyMe(int id, string data)
{
   string url = $"https://localhost:44382/api/isc/getdata?id=" + id + "&data=" + data;
   ApiHelper.InitializeClient();
   string _apiResult = await APIProcessor.LoadApi(url);     
}

API 助手

public static class ApiHelper
{
    public static HttpClient ApiClient { get; set; }
    public static void InitializeClient() 
    {
        ApiClient = new HttpClient();
        ApiClient.DefaultRequestHeaders.Accept.Clear();
        ApiClient.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/jason"));
    }
}

API处理器

public class APIProcessor
{
    public static async Task<string> LoadApi(string url)
    {
        using (HttpResponseMessage response = await ApiHelper.ApiClient.GetAsync(url))
        {
            if (response.IsSuccessStatusCode)
            {
                string _apiResult = await response.Content.ReadAsStringAsync();
                return _apiResult;
            }
            else
            {
                throw new Exception(response.ReasonPhrase);
            }
        }
    }
}

我想在 foreach 循环中调用我的 API,如下所示

using (myEntities _context = new myEntities ())
{
    foreach (var item in _context.items.Where(s => s.id >= 1 && s.id <= 500))
      {
          applyMe(item.id, item.data);
      }
 }

由于async await,API 尚未调用 :( 请问这个问题怎么解决?

提前致谢

【问题讨论】:

  • await getData(...?
  • @Charlieface 忘记API的名字,我改了
  • OK await applyMe(... 函数的名称显然不是我的意思。你需要await一个异步函数
  • @Charlieface 怎么样?
  • 一直是async Task,直到你到达UI事件处理程序,然后使用async void。所以声明private async Task applyMe(...

标签: c# api asynchronous httpclient


【解决方案1】:

使用 Task.WhenAll()。它返回一个等待所有其他任务完成时完成的任务。最后你需要等待而不阻塞线程。见microsoft doc

using (myEntities _context = new myEntities ())
{
    await Task.WhenAll(_context.items
                               .Where(s => s.id >= 1 && s.id <= 500)
                               .Select(s => applyMe(item.id, item.data))
                      );
}

重要提示! applyMe 应该返回一个 Task 而不是保持无效。不推荐使用 async void 模式。

【讨论】:

    【解决方案2】:

    两个小调整来完成这项工作: 第一个任务是无效的

    private async Task getData(int id, string data)
    {
        string url = $"https://localhost:44382/api/isc/getdata?id=" + id + "&data=" + data;
        ApiHelper.InitializeClient();
        string _apiResult = await APIProcessor.LoadApi(url);     
    }
    

    其次,等待 getData 调用

    using (myEntities _context = new myEntities ())
    {
        foreach (var item in _context.items.Where(s => s.id >= 1 && s.id <= 500))
          {
              await getData(item.id, item.data);
          }
     }
    

    【讨论】:

      【解决方案3】:

      你可以使用IAsyncEnumerable&lt;MyModel&gt; (docs)

      public IAsyncEnumerable<MyModel> GetItems()
      {
          IQueryable<T> query = this._context.items;
      
          query = query.Where(s => s.id >= 1 && s.id <= 500);
      
          return query.AsAsyncEnumerable();
      }
      

      并将其用于:

      IAsyncEnumerable<MyModel>> items = GetItems();
      await foreach (var myModel in items)
      {
          //Call external api         
      }                
      

      【讨论】:

        猜你喜欢
        • 2019-03-24
        • 1970-01-01
        • 2016-09-26
        • 2012-07-19
        • 1970-01-01
        • 2023-03-24
        • 2015-07-15
        • 2017-10-19
        • 2013-09-27
        相关资源
        最近更新 更多