2015-12-10 3 views
0

Я использовал в прошлом BackgroundWorker в приложении Windows Form. Для моего нового упражнения мне нужно использовать методы async внутри рабочего, и я немного немного смущен.BackgroundWorker, который использует методы async HttpClient

Это моя структура кода. В случае загрузки формы я создание BackgroundWorker объекта и установки события

private void fMain_Load(object sender, EventArgs e) { 
    bw = new BackgroundWorker(); 
    bw.WorkerReportsProgress = true; 
    bw.DoWork += new DoWorkEventHandler(bw_DoWork); 
    bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged); 
    bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted); 
} 

Когда пользователь нажимает кнопку, я начинаю работник

private void btnGenerate_Click(object sender, EventArgs e) { 
    Settings settings = new Settings(); 
    pbCounter.Visible = true; 
    btnGenerate.Enabled = false; 
    bw.RunWorkerAsync(settings); 
} 

И это код работника

private async void bw_DoWork(object sender, DoWorkEventArgs e) { 
    try { 
     for (int ix = 1; i <= 100; i++) { 
      using (var client = new HttpClient()) { 
       [???? how to call and wait here ????] 
       HttpResponseMessage response = await client.PostAsync("endpoint", new StringContent(JsonConvert.SerializeObject(formContent), Encoding.UTF8, "application/json")); 
      } 

      //The counter will keep track of your process 
      Application.DoEvents(); 
      int percentage = ix * 100/settings.TotalRuns; 
      bw.ReportProgress(percentage); 
     } 
    } 
    catch (Exception ex) { 
     MessageBox.Show(ex.Message, "Gift Creator", MessageBoxButtons.OK, MessageBoxIcon.Error); 
    } 
} 
+1

Я не думаю, что «BackgroundWorker» хорошо играет с асинхронным ожиданием. Вероятно, вы должны использовать что-то другое (или создать его). – i3arnon

+0

Это не может работать. Если вы создаете обработчик 'DoWork'' async' и используете 'await' внутри, метод возвращается туда, и рабочий фон будет завершен. Я думаю, что вам не нужен фоновой работник при использовании async, но нужно подумать о том, как тогда будет вести отчет. –

+0

@ RenéVogt: справа. Я думал бросить фонового работника. Однако мне очень нравится, как он обрабатывает уведомление о ходе. Любое предложение? – Lorenzo

ответ

2

Если вы используете async и await, вам не нужен рабочий фон. Фактически, ваш фоновый рабочий не работал бы, потому что управление возвращается вызывающему, когда вы используете await. И когда обработчик DoWork возвращает управление своему вызывающему, фоновый работник прекратит работу и не продолжит свои оставшиеся задачи.

Так я хотел бы сделать кнопку обработчик async и делать запросы HTTP там:

private async void btnGenerate_Click(object sender, EventArgs e) 
    { 
     const int totalRuns = 5; 
     pbCounter.Visible = true; 
     pbCounter.Minimum = 0; 
     pbCounter.Maximum = totalRuns; 
     pbCounter.Value = 0; 
     btnGenerate.Enabled = false; 

     try 
     { 
      for (int i = 1; i <= totalRuns; i++) 
      { 
       using (var client = new HttpClient()) 
        await client.PostAsync("endpoint", new StringContent(JsonConvert.SerializeObject(formContent), Encoding.UTF8, "application/json")); 
       pbCounter.Value = i; 

      } 
     } 
     catch (Exception ex) 
     { 
      MessageBox.Show(ex.Message, "Gift Creator", MessageBoxButtons.OK, MessageBoxIcon.Error); 
     } 

     btnGenerate.Enabled = true; 
    } 

Так что этот обработчик возвращает управление вызывающему абоненту (сказать упрощённым: пользовательский интерфейс) во время ожидания запрос http. Когда запрос будет завершен, выполнение продолжается на линии pbCounter.Value = i - и в потоке пользовательского интерфейса! Таким образом, вы можете безопасно обновлять индикатор выполнения, потому что вы не делаете это из другого потока.

Надеюсь, это вам поможет. Обратите внимание, что я установил pbCounter.Maximum в число циклов, которые вы собираетесь запустить, поэтому вам не нужно вычислять процент.

+0

Спасибо, что помогли! – Lorenzo