Search code examples
c#httpclientgetasync

How to wait for HttpClient GetAsync call until it returns the request in C#


I am trying to get data by the HttpClient. Data vary in size, it could be from few bytes to megabyte. I noticed many times my application exist even before it returns from the GetAsync. How can I wait until GetAsync complete it call? From the main app:-

        backup.DoSaveAsync();
        Console.ForegroundColor = ConsoleColor.Yellow;
        Console.BackgroundColor = ConsoleColor.Red;
        // My app exist by printing this msg, wihout getting any data. 
        // someitmes it gets data and other times it gets notinng.
        // I used sleep to wait to get the call completed. 
        Console.WriteLine("\nBackup has done successfully in SQL database")

        public async void DoSaveAsync()
        {
            using (var client = GetHttpClient(BaseAddress, path, ApiKey))
            {
                Stream snapshot = await  GetData(client, path);

                if (snapshot != Stream.Null)
                {
                    snapshot.Position = 0;
                    SaveSnapshot(snapshot);
                }
            }
        }

   private async Task<Stream> GetData(HttpClient client, string path)
    {
        HttpResponseMessage response = null;
        try
        {
            response = await client.GetAsync(path);
            System.Threading.Thread.Sleep(5000);
            if (response.IsSuccessStatusCode == false)
            {
                Console.WriteLine($"Failed to get snapshot");
                return Stream.Null;
            }
            return await response.Content.ReadAsStreamAsync();
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            return Stream.Null;
        }
    }

Code update after the comments and answer:

     // in my main app, I have this code. 
     // How can I get the completed task or any error return by the task here.
    backup.DoBackupAsync().Wait();

    public async Task<Stream> DoSaveAsync()
    {
        using (var client = GetHttpClient(BaseAddress, SnapshotPath, ApiKey))
        {
            try
            {
                Stream snapshot = await GetSnapshot(client, SnapshotPath);

                if (snapshot != Stream.Null)
                {
                    snapshot.Position = 0;
                    SaveSnapshot(snapshot);
                }
                return snapshot;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return null;
            }

        }
    }

Solution

  • As the method is async, the backup.DoSaveAsync() line only start a Task but doesn't wait for the result, so you may call Console.ReadLine (and possibly exit your program) before the task is completed. You should return Task instead of void - it's generally bad design to have a void async method, and younhave to await backup.DoSaveAsync() either via await (if you call from an async method), either via .Wait().

    Also, in case of error in GetData, you don't return any error for DoSaveAsync - you may want to deal with this, in the current code, you would print "Failed to get snapshot" and then "Backup has done successfully in SQL database". Consider to not use Console.ReadLine in GetData and return a Task in DoSaveAsync indicating success

    No need to put a thread.sleep here - you already await the result.