2012-06-14 136 views
0

首先,我對C#和.NET框架有點新,但我試圖實現的是(恕我直言)相當簡單的目標,但我仍然遇到一些麻煩。HttpWebRequest.BeginGetRequestStream阻止UI線程

我的目標是使用WebRequest類將數據發佈到Web服務。我已經通過了documentation和實例閱讀,特別是這部分:

的BeginGetRequestStream方法需要一些同步設置任務 之前完成(DNS解析,代理檢測和TCP套接字 連接,例如)此方法變得異步。作爲 結果,不應在用戶界面(UI) 線程上調用此方法,因爲它可能需要一些時間(通常爲幾秒)。

參考鏈接的例子,我如何使方法GetRequestStreamCallbackGetResponseCallback在後臺線程中運行?

這是我走到這一步:

private void startTask() 
     { 
      BackgroundWorker worker = new BackgroundWorker(); 

      worker.DoWork += new DoWorkEventHandler(worker_DoWork); 
      worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged); 
      worker.RunWorkerAsync(); 
     } 

     void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) 
     { 
      updateStatus(e.ProgressPercentage); 
     } 

     void worker_DoWork(object sender, DoWorkEventArgs e) 
     { 
      BackgroundWorker worker = sender as BackgroundWorker; 

      postData = /* data to be posted */; 
      byte[] postBytes = Encoding.UTF8.GetBytes(postData); 

      HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://example.com"); 
      request.ContentType = "application/x-www-form-urlencoded"; 
      request.ContentLength = postBytes.Length; 
      request.Method = "POST"; 

      request.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), request); 
     } 

     private void GetRequestStreamCallback(IAsyncResult result) 
     { 
      HttpWebRequest request = (HttpWebRequest)result.AsyncState; 

      using (Stream stream = request.EndGetRequestStream(result)) 
      { 
       stream.Write(Encoding.UTF8.GetBytes(postData), 0, Encoding.UTF8.GetBytes(postData).Length); 
       stream.Close(); 
      } 

      request.BeginGetResponse(new AsyncCallback(GetResponseCallback), request); 
     } 

     private void GetResponseCallback(IAsyncResult result) 
     { 
      HttpWebRequest request = (HttpWebRequest)result.AsyncState; 
      HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result); 
      Console.WriteLine(response.StatusDescription); 
     } 

我已經使用了BackgroundWorker與UI交互,但我打開替代解決方案的原因。我的問題是:當執行流程到達worker_DoWork函數的末尾時,工作器是否終止?甚至回調函數是由工作人員自己執行的?如果沒有,是否有替代方案可以讓整個代碼在單獨的線程中運行?

我爲(可能)愚蠢的問題表示歉意,但正如我所說的,我對.NET相當陌生,但我仍然沒有把握線程池和線程池的概念。

回答

2

BackgroundWorker線程在DoWork函數結束時完成,然後在啓動BackgroundWorker的線程上引發RunWorkerCompleted。

在您的示例中,GetResponseCallback將在不同的線程上運行,因爲調用request.BeginGetRequestStream的線程將在DoWork結束時返回到池。

爲了簡單起見,您可以使用同步版本或請求/響應方法(例如request.GetRequestStream),因爲您不再處於UI線程中。您的UI線程可以偵聽RunWorkedCompleted以從UI線程中獲取調用結果。

+0

這正是第一個超越我的想法的解決方案。感謝您的確認。但是,出於好奇,有沒有辦法在函數的同一個線程中運行回調函數,將它們鏈接到事件(在這種情況下,worker_DoWork和GetRequestStreamCallback,可能在worker_DoWork中使用某種等待)? –

+1

一種方法是使用AutoResetEvent。在DoWork中調用BeginGetRequestStream後調用event1.WaitOne(),然後在GetResponseCallback中調用event1.Set()。後臺工作線程將恢復。 – Japple

+0

再次感謝,工作就像一個魅力。 –