2012-05-06 55 views
1

我正在做一個簡單的應用程序來連接到web服務,並且我在管理異步請求時遇到問題。如何在不阻塞主線程的情況下返回異步HttpWebResponse?

問題在於函數ProcessRequest,它基本上使異步HttpWebRequest,並返回HttpWebResponse。由於請求是異步的,我在返回值方面遇到了問題,並且調用了ProcessRequest方法並等待HttpWebResponse對象。

順便說一下,請求本身工作完美,已經在功能內測試,所以我不需要返回HttpWebResponse。

我希望自己清楚,正如我所說,這是我第一次觸摸c#,.NET和Windows Phone開發。 (和WebRequests爲此事)

的錯誤是Visual Studio是拋是:

1: Since 'System.AsyncCallback' returns void, a return keyword must not be followed by an object expression 
2: Cannot convert lambda expression to delegate type 'System.AsyncCallback' because some of the return types in the block are not implicitly convertible to the delegate return type  

這是代碼:

namespace SimpleNoteConcept 
{ 
public sealed class SimpleNote 
{ 
    private static readonly SimpleNote _instance = new SimpleNote(); 
    private static string _authToken = string.Empty; 
    private static string _email = string.Empty; 
    private static string _authQsParams 
    { 
     get 
     { 
      if (string.IsNullOrEmpty(_authToken)) throw new SimpleNoteConceptAuthorisationException(); 
      return string.Format("auth={0}&email={1}", _authToken, _email); 
     } 
    } 

    private SimpleNote() { } 

    public static SimpleNote Instance 
    { 
     get { return _instance; } 
    } 

    public bool Connect(string email, string password) 
    { 
     try 
     { 
      StringParamCheck("email", email); 
      StringParamCheck("password", password); 

      var data = string.Format("email={0}&password={1}", email, password); 
      var bytes = Encoding.GetEncoding("utf-8").GetBytes(data); 
      data = Convert.ToBase64String(bytes); 

      using (var resp = ProcessRequest(loginPath, "POST", content: data)) 
      { 
       if (resp != null) 
       { 
        _authToken = resp.Cookies["auth"].Value; 
        _email = email; 
        System.Diagnostics.Debug.WriteLine("Connection established! -> " + _authToken); 
        return true; 
       } 
       return false; 
      } 
     } 
     catch (Exception) 
     { 
      throw; 
     } 

    } 

    public void GetIndex(int length = 100, string mark = null, DateTimeOffset? since = null) 
    { 
     try 
     { 
      string sinceString = null; 
      if (since.HasValue) 
       sinceString = Json.DateTimeEpochConverter.DateToSeconds(since.Value); 

      var queryParams = string.Format("{0}&length={1}&mark={2}&since={3}", _authQsParams, length, mark, sinceString); 
      using (var resp = ProcessRequest(indexPath, "GET", queryParams)) 
      { 
       var respContent = ReadResponseContent(resp); 
       System.Diagnostics.Debug.WriteLine("GetIndex: " + respContent.ToString()); 
       //var notes = JsonConvert.DeserializeObject<Objects.NoteEnumerable<T>>(respContent); 
       //return notes; 
      } 
     } 
     catch (WebException ex) 
     { 
      var resp = (HttpWebResponse)ex.Response; 
      switch (resp.StatusCode) 
      { 
       //401 
       case HttpStatusCode.Unauthorized: 
        throw new SimpleNoteConceptAuthorisationException(ex); 
       default: 
        throw; 
      } 
     } 
     catch (Exception) { throw; } 
    } 

    /// <summary> 
    /// Generic method to process a request to Simplenote. 
    /// All publicly expose methods which interact with the store are processed though this. 
    /// </summary> 
    /// <param name="requestPath">The path to the request to be processed</param> 
    /// <param name="method">The HTTP method for the request</param> 
    /// <param name="content">The content to send in the request</param> 
    /// <param name="queryParams">Queryparameters for the request</param> 
    /// <returns>An HttpWebResponse continaing details returned from Simplenote</returns> 
    private static HttpWebResponse ProcessRequest(string requestPath, string method, 
                string queryParams = null, string content = null) 
    { 
     try 
     { 
      var url = string.Format("{0}{1}{2}", "https://", domainPath, requestPath); 
      if (!string.IsNullOrEmpty(queryParams)) url += "?" + queryParams; 
      var request = WebRequest.Create(url) as HttpWebRequest; 
      request.CookieContainer = new CookieContainer(); 
      request.Method = method; 

      request.BeginGetRequestStream((e) => 
      { 
       using (Stream stream = request.EndGetRequestStream(e)) 
       { 
        // Write data to the request stream 
        var bytesBody = Encoding.GetEncoding("utf-8").GetBytes(content); 

        stream.Write(bytesBody, 0, bytesBody.Length); 
        stream.Close(); 
        stream.Dispose(); 
       } 
       request.BeginGetResponse((callback) => 
       { 
        try 
        { 
         HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(callback); 
         return response; 

        } 
        catch (WebException ex) 
        { 
         using (WebResponse Exresponse = ex.Response) 
         { 
          HttpWebResponse httpResponse = (HttpWebResponse)Exresponse; 
          System.Diagnostics.Debug.WriteLine("Error code: {0}", httpResponse.StatusCode); 
          using (Stream str = Exresponse.GetResponseStream()) 
          { 
           string text = new StreamReader(str).ReadToEnd(); 
           System.Diagnostics.Debug.WriteLine(text); 
          } 
         } 
        } 
        catch (Exception ex) 
        { 
         System.Diagnostics.Debug.WriteLine("Message: " + ex.Message); 
        } 
       }, request); 
      }, request); 

     } 
     catch (Exception) 
     { 
      throw; 
     } 
    } 

    /// <summary> 
    /// Reads the content from the response object 
    /// </summary> 
    /// <param name="resp">The response to be processed</param> 
    /// <returns>A string of the response content</returns> 
    private static string ReadResponseContent(HttpWebResponse resp) 
    { 
     if (resp == null) throw new ArgumentNullException("resp"); 
     using (var sr = new StreamReader(resp.GetResponseStream())) 
     { 
      return sr.ReadToEnd(); 
     } 
    } 

    /// <summary> 
    /// String parameter helper method. 
    /// Checks for null or empty, throws ArgumentNullException if true 
    /// </summary> 
    /// <param name="paramName">The name of the paramter being checked</param> 
    /// <param name="value">The value to check</param> 
    private void StringParamCheck(string paramName, string value) 
    { 
     if (string.IsNullOrEmpty(value)) throw new ArgumentNullException(paramName, "Value must not be null or string.Empty"); 
    } 

} // Class End 

} // Namespace End 

提前感謝!

+0

你的ProcessRequest方法會在你的委託甚至執行之前完成,對嗎?我認爲你需要在C#5中使用新的異步/等待功能,但是我從來沒有親自使用過它們,也不確定它們是否可用於WP7 7.1 ... http://www.codeproject.com/Articles/127291/C-5-0-vNext-New-Asynchronous-Pattern –

+1

這可能有助於簡化異步代碼,但由於它仍然是CTP,我不會實現它。不管怎麼說,還是要謝謝你。 是的,它可用於WP7平臺。 – asendra

回答

1

不能像平常一樣進行異步編程。這裏.Net在不同的線程中運行異步部分,它們如何進行通信?所以你可以做的是用你的ProcessRequest方法傳遞一個委託。這將採用HttpWebResponse的參數。

打電話給你的方法是這樣的:

Action<HttpWebResponse> actionDelegate = DoAfterGettingResponse; 
ProcessRequest(indexPath, "GET", actionDelegate, queryParams); 

功能是處理響應

public static void DoAfterGettingResponse(HttpWebResponse resp) 
{ 
    if (resp != null) 
    { 
     _authToken = resp.Cookies["auth"].Value; 
     _email = email; 
     System.Diagnostics.Debug.WriteLine("Connection established! -> " + _authToken); 

    } 

    //Do anything else with the response 
}  

的ProcessRequest將有新的簽名。

private static HttpWebResponse ProcessRequest(
    string requestPath, string method, Action<HttpWebResponse> reponseDelegate, 
    string queryParams = null, string content = null) 
{ 
    //Do what you are already doing   
} 

而且,你正在返回響應的地方,只是做

HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(callback); 
responseDelegate(response); 

你可以做這樣或使用事件,火傳遞HttpWebResponse作爲參數的事件,以及如何在聽衆的響應。

+0

這個定義是有效的,它基本上也是我的想法。將回調傳遞給ProcessRequest方法,並在請求完成時執行該回調。謝謝!無論如何,如果有人知道更好的方法,請分享! – asendra

相關問題