2015-12-12 3 views
4

Мне нужно знать, есть ли способ выполнить DownloadPage (результат) без немедленного перехода к Console.ReadKey() в моем основном методе.Console.ReadLine в async-методе не блокирует прогрессирование.?

Что происходит, когда запускается DownloadPage, но после отображения «Хотите сохранить это в .txt-файле? [Y/N]», программа заканчивается после ввода любой клавиши. Сначала я попробовал весь метод внутри GetPageHTML, но он продолжает ломаться, как только я пытаюсь получить пользовательский ввод.

Я все еще изучаю C#, и я не знаю, как подойти к проблеме и исправить ее. Может ли кто-нибудь помочь?

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

ответ

8

Ну да, вы не дождались завершения операции async. Вы должны объявить метод вернуть Task вместо этого, как это:

static async Task GetPageHtml(string _url) 

, а затем ждать его в вашем Main метод:

GetPageHtml(url).Wait(); 

Теперь обычно, блокирование для задачи, чтобы завершить синхронно, как это плохая идея, потому что вы можете заблокировать тот же поток, который должен выполнить эту работу, но основной поток консольного приложения не имеет контекста синхронизации, поэтому продолжения в методе async будут выполняться в потоке пула потоков ... так что это Wait() безопасно.

Конечно, это несколько поражает часть использования async - но если вы просто изучаете async, это нормально.

В общем, только раз, async метод должен быть объявлен void так, что вы можете использовать его в качестве обработчика события.

+0

будет ли 'ConfigureAwait (...)' в консольном приложении давать импульс? –

+2

@MikeMazmanyan: Нет, это в принципе не имело бы никакого значения, поскольку в любом случае контекста синхронизации не существует. 'ConfigureAwait' не следует рассматривать как метод производительности - он используется, чтобы убедиться, что продолжение не выполняется на неподходящем потоке. –

3

В качестве альтернативы JonSkeet's ответ вы также можете использовать StephenCleary'sAsyncEx Library, то вы можете await ваш метод GetPageHTML(). Таким образом, ваш код будет выглядеть так:

using Nito.AsyncEx;  
static void Main(string[] args) 
{ 
    AsyncContext.Run(() => MainAsync(args)); 
}   

static async void MainAsync(string[] args) 
{ 
    Console.Write("Enter URL: "); 
    string url = Console.ReadLine(); 

    await GetPageHTML(url); 
    Console.ReadKey(); 
} 
Смежные вопросы