Home > Software engineering >  Using await for a async function inside a for loop
Using await for a async function inside a for loop

Time:12-15

I am running a bunch of convert-to-pdf api calls through MS Graph and then returning the base64 encoded strings to the frontend for processing in pdf.js. However, I wanted to speed this up by adding async and await to do as many api calls as I can in the shortest time (not using batch in MS Graph). However, it is unclear if this code is looping through the for loop to the next call or waiting for each await result individually which I do not want. I want to keep looping through for each request and then return the final result once all the calls have finished.

        public async Task<ActionResult> PDFVersionsToBase64([FromForm] string ID)
    {
        //Using FormData on frontend
        //checking ID exists on searching in dashboard
        if (String.IsNullOrEmpty(ID))
        {
            return Ok(new { Result = "Failed" });
        }
        else
        {

            String query = "select * from dbo.function(@ID)";
            using (var connection = new SqlConnection(connectionString))
            {
                var documents = connection.Query<QuestionDocuments>(query, new { ID = ID});

                foreach (var file in documents)
                {
                    var fullPath = Path.Combine(fileDirectory, file.path);
                    using (var memoryStream = await oneDrive.DriveItemConvertToPdfAsync(SharedDriveID, fullPath, "path"))
                    {
                        byte[] buffer = new byte[memoryStream.Length];
                        memoryStream.Read(buffer, 0, (int)memoryStream.Length);
                         file.Base64 = Convert.ToBase64String(buffer);
                    }
                }

                return Ok(documents);

            }
        }
    }

        public async Task<Stream> DriveItemConvertToPdfAsync(string DriveID, string PathOrDriveItemID, string SearchType)
    {
        Stream response = null;
        try
        {
            var queryOptions = new List<QueryOption>()
            {
                new QueryOption("format", "pdf")
            };

            if (SearchType == "path")
            {
                response= await _graphServiceClient.Me.Drives[DriveID].Root
                .ItemWithPath(PathOrDriveItemID)
                .Content
                .Request(queryOptions)
                .GetAsync();
            }
            else if (SearchType == "id")
            {
                response = await _graphServiceClient.Me.Drives[DriveID].Items[PathOrDriveItemID]
                .Content
                .Request(queryOptions)
                .GetAsync();
            }
        }
        catch (ServiceException ex)
        {
            Console.WriteLine($"Error deleting file: {ex.ToString()}");
        }
        return response;
    }

CodePudding user response:

You need to start all tasks and then wait for them all at once.

var files = documents.ToArray();

var tasks = files.Select(file =>
    oneDrive.DriveItemConvertToPdfAsync(
        SharedDriveID, 
        Path.Combine(fileDirectory, file.Path), 
        "path"));

var streams = await Task.WhenAll(tasks);

for(var i = 0; i < files.Length; i  )
{
    var file = files[i];
    var stream = streams[i];
    using (var memoryStream = stream)
    {
        byte[] buffer = new byte[memoryStream.Length];
        memoryStream.Read(buffer, 0, (int)memoryStream.Length);
         file.Base64 = Convert.ToBase64String(buffer);
    }
}

Or if you want to use the ReadAsync method of the stream instead:

var tasks = documents.Select(async file => {
    var stream = await oneDrive.DriveItemConvertToPdfAsync(
        SharedDriveID, 
        Path.Combine(fileDirectory, file.Path), 
        "path");
        
    using (var memoryStream = stream)
    {
        byte[] buffer = new byte[memoryStream.Length];
        await memoryStream.ReadAsync(buffer, 0, (int)memoryStream.Length);
        file.Base64 = Convert.ToBase64String(buffer);
    }
});

await Task.WhenAll(tasks);
  • Related