2013-02-26 103 views
3

我試圖在WinForms應用程序中異步使用HttpWebRequestHttpWebResonse而不會阻塞我的UI線程。異步使用HttpWebRequest而不阻塞UI線程

我看到這個similar SO Question,它解釋瞭如何做到這一點。但是,我不能100%確定接受的答案是正確的做法。接受的答案是使用BeginGetResponse

按照MSDN documentation

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

有人可以請我提供正確的方法來做到這一點。這裏是我的,我試圖做工作「正常」,而不擋住了我的UI線程C#功能:

private IDictionary<string, object> CreateWebRequest(string endPoint, string method, string data, bool addAuthHeader) 
    { 
     var req = (HttpWebRequest)WebRequest.Create(endPoint); 
     req.Method = method; 
     if (addAuthHeader) 
     { 
      req.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + _accessToken.AccessToken); 
     } 

     if (!string.IsNullOrEmpty(data)) 
     { 
      var utfenc = new UTF8Encoding(); 
      byte[] buffer = utfenc.GetBytes(data); 
      req.ContentLength = buffer.Length; 
      req.ContentType = "application/x-www-form-urlencoded"; 

      using (Stream strm = req.GetRequestStream()) 
      { 
       strm.Write(buffer, 0, buffer.Length); 
       strm.Close(); 
      } 
     } 

     HttpWebResponse response = null; 
     try 
     { 
      response = (HttpWebResponse)req.GetResponse(); 
     } 
     catch (WebException e) 
     { 
      if (_accessToken == null) 
      { 
       throw; 
      } 
      var responseError = (HttpWebResponse)e.Response; 
      if (responseError.StatusCode == HttpStatusCode.Unauthorized) 
      { 
       var stackTrace = new StackTrace(); 
       var q = stackTrace.GetFrame(1).GetMethod().Name; 
       RefreshAccessCode(); 

       req = (HttpWebRequest)WebRequest.Create(endPoint); 
       req.Method = method; 
       if (addAuthHeader) 
       { 
        req.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + _accessToken.AccessToken); 
       } 
       response = (HttpWebResponse)req.GetResponse(); 
      } 
     } 

     string jsonResponse = null; 

     if (response != null) 
      using (Stream stream = response.GetResponseStream()) 
      { 
       if (stream != null) 
       { 
        using (var reader = new StreamReader(stream)) 
        { 
         jsonResponse = reader.ReadToEnd(); 
        } 
       } 
      } 

     return DeserializeResponse(jsonResponse); 
    } 
+0

是不是@ Isak對另一個問題的回答你鏈接了你要找的東西? – vlad 2013-02-26 21:14:05

回答

3

如果你打開另外WebRequest的東西,我的System.Net.WebClient風扇。它使用System.Threading.Tasks而不是BeginGetResponse()和EndGetResonse()。

public async Task<Dictionary<string, object>> CreateWebRequest(string endPoint, string method, string data, bool addAuthHeader) 
{ 
    WebClient client = new WebClient(); 

    if (addAuthHeader) 
    { 
     client.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + _accessToken.AccessToken); 
    } 

    byte[] buffer = null; 

    if (!string.IsNullOrEmpty(data)) 
    { 
     var utfenc = new UTF8Encoding(); 
     buffer = utfenc.GetBytes(data); 
    } 
    else 
    { 
     buffer = new byte[0]; 
    } 

    return await client.UploadDataTaskAsync(endPoint, method, buffer) 
     .ContinueWith((bytes) => 
      { 
       string jsonResponse = null; 

       using (var reader = new StreamReader(new MemoryStream(bytes))) 
       { 
        jsonResponse = reader.ReadToEnd(); 
       } 

       return DeserializeResponse(jsonResponse); 
      }); 
    } 
} 
0

要使用現有的代碼,再加上一點意在UI線程上執行的方法,以及在單獨的線程上創建您的Web請求。當Web請求完成後,您可以調用UI線程上的最終方法。所以,一個簡單的版本是:

//do some stuff that wont block the ui thread here 
ThreadPool.QueueUserWorkItem((o) => 
{ 
    IDictionary<string, object> result = 
     CreateWebRequest("lalala", "lol", "butts", true); 
    BeginInvoke(OnAsyncWebRequestComplete, result); 
}, null); 

private void OnAsyncWebRequestComplete(IDictionary<string, object> result) 
{ 
    //do some stuff on the UI thread here 
}