Abdulsalam Elsharif
Abdulsalam Elsharif

Reputation: 5111

Calling API inside foreach loop in C#

I have the following function that call my 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 Helper

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"));
    }
}

APIProcessor

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);
            }
        }
    }
}

I want to call my API inside foreach loop as below

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

The API not calling yet because of async await :( Please how can I solve this issue?

Upvotes: 1

Views: 2281

Answers (3)

Shahar Shokrani
Shahar Shokrani

Reputation: 8762

You could use IAsyncEnumerable<MyModel> (docs)

public IAsyncEnumerable<MyModel> GetItems()
{
    IQueryable<T> query = this._context.items;

    query = query.Where(s => s.id >= 1 && s.id <= 500);

    return query.AsAsyncEnumerable();
}

And use it with:

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

Upvotes: 0

Erik Sijnja
Erik Sijnja

Reputation: 1

Two small adjustments to make this work: First Task iso void

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);     
}

and second, await the getData call

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);
      }
 }

Upvotes: 0

verbedr
verbedr

Reputation: 2270

Use Task.WhenAll(). It returns an awaitable that will get completed when all other tasks are finished. In the end you need to wait without blocking the thread. see 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))
                      );
}

Important! The applyMe should return a Task and not remain void. The async void pattern is not recommended.

Upvotes: 2

Related Questions