簡體   English   中英

來自WPF的異步Web服務請求

[英]Async Web Service Requests from WPF

我嘗試過(但失敗了)從WPF應用程序進行異步Web服務調用。

當您在GUI上按“發送”按鈕時,我在我的代碼中實現了應該執行該工作的BackgroundWorker 有時會執行預期的操作 ,但最終實際上並沒有異步運行。

當您在我的GUI中按下按鈕時,將觸發以下代碼:

private void btnSend_Click(object sender, RoutedEventArgs e)
{
    sQuantity = boxQuantity.Text;
    progressBar.Maximum = double.Parse(sQuantity);
    worker.RunWorkerAsync();
}

sQuantity只是一個帶有數字的盒子。 它將確定您一次發送到Web服務的請求數量。

progressBar是您所期望的:進度條。

worker.RunWorkerAsync()是我調用DoWork方法的地方。 看起來像這樣:

void worker_DoWork(object sender, DoWorkEventArgs e)
{
    EnableButton(false);
    List<LoanRequestNoCreditScoreDTO> dtoList = GetData();
    foreach (LoanRequestNoCreditScoreDTO dto in dtoList)
    {
        using (LoanBrokerWS.LoanBrokerWSClient client = new LoanBrokerWS.LoanBrokerWSClient())
        {
            try
            {
                Task<LoanQuoteDTO> lq = RequestQuote(dto, client);
                LoanQuoteDTO response = lq.Result;
                lq.Dispose();
                String responseMsg = response.SSN + "\n" + response.interestRate + "\n" + response.BankName + "\n------\n";
                AppendText(responseMsg);
                worker_ProgressChanged();
            }
            catch (Exception ex)
            {
                AppendText(ex.Message + "\n" + ex.InnerException.Message + "\n");
                worker_ProgressChanged();
            }
        }
    }
    EnableButton(true);
}

最終,這是我理所當然的地方。 我希望應用程序發送與用戶指定數量一樣多的請求。 因此,如果我寫了10封,我將發送10封請求。 RequestQuote()方法調用以下代碼:

private async Task<LoanQuoteDTO> RequestQuote(LoanRequestNoCreditScoreDTO dto, LoanBrokerWS.LoanBrokerWSClient client)
{
    LoanQuoteDTO response = await client.GetLoanQuoteAsync(dto.SSN, dto.LoanAmount, dto.LoanDuration);
    return response;
}

如何使DoWork方法實際發送請求異步?

就UI線程而言,代碼原樣是異步的; 您要問的並發性是什么。 最好使用async / await完成任何類型的復雜I / O工作,因此我將淘汰您的后台工作人員,僅使用直接async

首先,按鈕處理程序將處理其自己的啟用/禁用和執行主要下載:

private async void btnSend_Click(object sender, RoutedEventArgs e)
{
  var quantity = int.Parse(boxQuantity.Text);
  btnSend.Enabled = false;
  await DownloadAsync(quantity);
  btnSend.Enabled = true;
}

主要下載將創建一個限速SemaphoreSlim (一種用於限制並發異步操作的通用類型),並等待所有單獨下載完成:

private async Task DownloadAsync(int quantity)
{
  var semaphore = new SemaphoreSlim(quantity);
  var tasks = GetData().Select(dto => DownloadAsync(dto, semaphore));
  await Task.WhenAll(tasks);
}

單獨的下載將各自先限制自己的速率,然后再進行實際的下載:

private async Task DownloadAsync(LoanRequestNoCreditScoreDTO dto, SemaphoreSlim semaphore)
{
  await semaphore.WaitAsync();
  try
  {
    using (LoanBrokerWS.LoanBrokerWSClient client = new LoanBrokerWS.LoanBrokerWSClient())
    {
      var response = await RequestQuoteAsync(dto, client);
    }        
  }
  finally
  {
    semaphore.Release();
  }
}

對於執行進度報告,我建議使用用於該模式的類型( IProgress<T> / Progress<T> )。 首先,您決定要在進度報告中使用哪些數據; 在這種情況下,它可能只是一個字符串。 然后,創建進度處理程序:

private async void btnSend_Click(object sender, RoutedEventArgs e)
{
  var quantity = int.Parse(boxQuantity.Text);
  var progress = new Progress<string>(update =>
  {
    AppendText(update);
    progressBar.Value = progressBar.Value + 1;
  });
  progressBar.Maximum = ...; // not "quantity"
  btnSend.Enabled = false;
  await DownloadAsync(quantity, progress);
  btnSend.Enabled = true;
}

(請注意,原始代碼中的progressBar.Maximum = double.Parse(sQuantity);是錯誤的;您應將其設置為下載總數 )。

然后IProgress<string>剛被傳遞:

private async Task DownloadAsync(int quantity, IProgress<string> progress)
{
  var semaphore = new SemaphoreSlim(quantity);
  var tasks = GetData().Select(dto => DownloadAsync(dto, semaphore, progress));
  await Task.WhenAll(tasks);
}

當您有進度報告時,可以使用該實例:

private async Task DownloadAsync(LoanRequestNoCreditScoreDTO dto, SemaphoreSlim semaphore, IProgress<string> progress)
{
  await semaphore.WaitAsync();
  try
  {
    using (LoanBrokerWS.LoanBrokerWSClient client = new LoanBrokerWS.LoanBrokerWSClient())
    {
      var response = await RequestQuoteAsync(dto, client);
      progress.Report(response.SSN + "\n" + response.interestRate + "\n" + response.BankName + "\n------\n");
    }
  }
  catch (Exception ex)
  {
    progress.Report(ex.Message + "\n" + ex.InnerException.Message + "\n");
  }
  finally
  {
    semaphore.Release();
  }
}

如果您使用await關鍵字調用RequestQuote,則在每次調用中它都將等待響應,並且您無法進行其他響應。 因此,只需將代理的“ 完成的事件處理程序 ”用於異步方法,然后再調用RequestQuote方法並在事件處理程序中給出響應即可。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM