Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Console.ReadLine in async method isn't blocking progression..?

Tags:

c#

I need to know if there's a way to execute DownloadPage(result) without immediately proceeding to Console.ReadKey() in my main method.

What's happening is that DownloadPage fires, but after displaying "Would you like to save this to a .txt file? [Y/N]", the program ends after typing any key. I originally tried the entire method inside of GetPageHTML, but it keeps breaking as soon as I try to get user input.

I'm still learning C# and I don't know how to approach the problem and correct it. Can anyone help?

using System;
using System.IO;
using System.Net.Http;
using System.Text.RegularExpressions;

namespace Programming_Challenge_4
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("Enter URL: ");
            string url = Console.ReadLine();

            GetPageHTML(url);
            Console.ReadKey();
        }

        static async void GetPageHTML(string _url)
        {
            try
            {
                using (HttpClient client = new HttpClient())
                using (HttpResponseMessage response = await client.GetAsync(_url))
                using (HttpContent content = response.Content)
                {
                    string result = await content.ReadAsStringAsync();
                    string title = Regex.Match(result, @"<title>\s*(.*?)\s*</title>").Groups[1].Value;
                    Console.WriteLine("Downloading HTML...\n\nTitle: {0}\n\n{1}\n\n", title, result);
                    DownloadPage(result);
                }
            }
            catch (Exception)
            {
                Console.WriteLine("There was an error reading the url \"{0}\".", _url);
            }
        }

        static void DownloadPage(string _html)
        {
            Console.WriteLine("Would you like to save this to a .txt file? [Y/N]");
            string saveFile = Console.ReadLine(); // CODE IS BREAKING HERE!

            if (saveFile.ToUpper() == "Y")
            {
                Console.Write("Please provide a file name: ");
                string name = Console.ReadLine();

                using (StreamWriter writer = new StreamWriter(name + ".txt"))
                {
                    writer.Write(_html);
                    writer.Close();
                }

                Console.WriteLine("HTML has been saved to {0}.txt!", name);
            }
        }
    }
}
like image 861
MDev20 Avatar asked Dec 15 '22 10:12

MDev20


1 Answers

Well yes - you're not waiting for the async operation to actually finish. You should declare the method to return Task instead, like this:

static async Task GetPageHtml(string _url)

and then wait for it in your Main method:

GetPageHtml(url).Wait();

Now normally, blocking for a task to complete synchronously like this is a bad idea because you could end up blocking the same thread that needs to do the work - but a console app's main thread doesn't have a synchronization context, so the continuations in the async method will run in a thread-pool thread... so this Wait() is safe.

Of course, this somewhat defeats part of the point of using async - but if you're just exploring async, that's fine.

In general, the only time an async method should be declared void is so that you can use it as an event handler.

like image 121
Jon Skeet Avatar answered Dec 17 '22 00:12

Jon Skeet