2011-10-18 102 views
2

我正在嘗試構建一個REST客戶端使用異步CTP。我是CTP的新手,因此,通過互聯網上的一些例子,我得到了一個爲發佈(GET或POST)而建立的類。這裏是類到目前爲止:PostSubmitter的異步CTP

using System; 
using System.Collections.Specialized; 
using System.IO; 
using System.Net; 
using System.Text; 
using System.Threading.Tasks; 
using System.Web; 

namespace RESTClient.Core { 

    /// <summary> 
    /// Submits post data to a url. 
    /// </summary> 
    public class PostSubmitter { 

     #region Backing Store 
     private string m_url = string.Empty; 
     private NameValueCollection m_values = new NameValueCollection(); 
     private PostTypeEnum m_type = PostTypeEnum.Get; 
     #endregion 

     #region Constructors 
     /// <summary> 
     /// Default constructor. 
     /// </summary> 
     public PostSubmitter() { 

     } 

     /// <summary> 
     /// Constructor that accepts a url as a parameter 
     /// </summary> 
     /// <param name="url">The url where the post will be submitted to.</param> 
     public PostSubmitter(string url) 
      : this() { 
      m_url = url; 
     } 

     /// <summary> 
     /// Constructor allowing the setting of the url and items to post. 
     /// </summary> 
     /// <param name="url">the url for the post.</param> 
     /// <param name="values">The values for the post.</param> 
     public PostSubmitter(string url, NameValueCollection values) 
      : this(url) { 
      m_values = values; 
     } 
     #endregion 

     #region Properties 
     /// <summary> 
     /// Gets or sets the url to submit the post to. 
     /// </summary> 
     public string Url { 
      get { 
       return m_url; 
      } 
      set { 
       m_url = value; 
      } 
     } 

     /// <summary> 
     /// Gets or sets the name value collection of items to post. 
     /// </summary> 
     public NameValueCollection PostItems { 
      get { 
       return m_values; 
      } 
      set { 
       m_values = value; 
      } 
     } 

     /// <summary> 
     /// Gets or sets the type of action to perform against the url. 
     /// </summary> 
     public PostTypeEnum Type { 
      get { 
       return m_type; 
      } 
      set { 
       m_type = value; 
      } 
     } 
     #endregion 

     /// <summary> 
     /// Posts the supplied data to specified url. 
     /// </summary> 
     /// <returns>a string containing the result of the post.</returns> 
     public async Task<String> Post() { 
      StringBuilder parameters = new StringBuilder(); 
      for (int i = 0; i < m_values.Count; i++) { 
       EncodeAndAddItem(ref parameters, m_values.GetKey(i), m_values[i]); 
      } 
      string result = await PostData(m_url, parameters.ToString()); 
      return result; 
     } 

     /// <summary> 
     /// Posts the supplied data to specified url. 
     /// </summary> 
     /// <param name="url">The url to post to.</param> 
     /// <returns>a string containing the result of the post.</returns> 
     public async Task<String> Post(string url) { 
      m_url = url; 
      return await this.Post(); 
     } 

     /// <summary> 
     /// Posts the supplied data to specified url. 
     /// </summary> 
     /// <param name="url">The url to post to.</param> 
     /// <param name="values">The values to post.</param> 
     /// <returns>a string containing the result of the post.</returns> 
     public async Task<String> Post(string url, NameValueCollection values) { 
      m_values = values; 
      return await this.Post(url); 
     } 

     /// <summary> 
     /// Posts data to a specified url. Note that this assumes that you have already url encoded the post data. 
     /// </summary> 
     /// <param name="postData">The data to post.</param> 
     /// <param name="url">the url to post to.</param> 
     /// <returns>Returns the result of the post.</returns> 
     private async Task<String> PostData(string url, string postData) { 
      HttpWebRequest request = null; 
      if (m_type == PostTypeEnum.Post) { 
       Uri uri = new Uri(url); 
       request = (HttpWebRequest)WebRequest.Create(uri); 
       request.Method = "POST"; 
       request.ContentType = "application/x-www-form-urlencoded"; 
       request.ContentLength = postData.Length; 
       using (Stream writeStream = await request.GetRequestStreamAsync()) { 
        UTF8Encoding encoding = new UTF8Encoding(); 
        byte[] bytes = encoding.GetBytes(postData); 
        writeStream.Write(bytes, 0, bytes.Length); 
       } 
      } 
      else { 
       Uri uri = new Uri(url + "?" + postData); 
       request = (HttpWebRequest)WebRequest.Create(uri); 
       request.Method = "GET"; 
      } 

      string result = string.Empty; 

      using (HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync()) { 
       using (Stream responseStream = response.GetResponseStream()) { 
        using (StreamReader readStream = new StreamReader(responseStream, Encoding.UTF8)) { 
         result = readStream.ReadToEnd(); 
        } 
       } 
      } 

      return result; 
     } 

     /// <summary> 
     /// Encodes an item and ads it to the string. 
     /// </summary> 
     /// <param name="baseRequest">The previously encoded data.</param> 
     /// <param name="dataItem">The data to encode.</param> 
     /// <returns>A string containing the old data and the previously encoded data.</returns> 
     private void EncodeAndAddItem(ref StringBuilder baseRequest, string key, string dataItem) { 
      if (baseRequest == null) { 
       baseRequest = new StringBuilder(); 
      } 
      if (baseRequest.Length != 0) { 
       baseRequest.Append("&"); 
      } 
      baseRequest.Append(key); 
      baseRequest.Append("="); 
      baseRequest.Append(HttpUtility.UrlEncode(dataItem)); 
     } 

    } 

} 

這是我如何使用它:

private void ButtonSubmit_Click(object sender, EventArgs e) { 
     ButtonReset.Enabled = false; 
     TextResponse.Text = String.Empty; 
     TextResponse.Text += "Begining..." + Environment.NewLine; 

     try { 
      TextResponse.Text += Task.Factory.StartNew(() => PostSomeData().Wait()); 
      //TextResponse.Text += PostSomeData(); 
      TextResponse.Text += Environment.NewLine; 
      TextResponse.Text += "Function Done!" + Environment.NewLine; 
     } 
     catch (Exception ex) { 
      TextResponse.Text += "Exception!" + Environment.NewLine + "Message: " + ex.Message + Environment.NewLine; 
     } 
     finally { 
      ButtonReset.Enabled = true; 
      TextResponse.Text += "Function Ended!"; 
     } 
    } 

    private async Task<String> PostSomeData() { 
     PostSubmitter post = new PostSubmitter(); 
     post.Url = TextURL.Text.Trim(); 

     post.PostItems.Add(TextParam01.Text.Trim(), TextValue01.Text.Trim()); 
     post.PostItems.Add(TextParam02.Text.Trim(), TextValue02.Text.Trim()); 
     post.PostItems.Add(TextParam03.Text.Trim(), TextValue03.Text.Trim()); 
     post.PostItems.Add(TextParam04.Text.Trim(), TextValue04.Text.Trim()); 
     post.PostItems.Add(TextParam05.Text.Trim(), TextValue05.Text.Trim()); 
     post.PostItems.Add(TextParam06.Text.Trim(), TextValue06.Text.Trim()); 
     post.PostItems.Add(TextParam07.Text.Trim(), TextValue07.Text.Trim()); 
     post.PostItems.Add(TextParam08.Text.Trim(), TextValue08.Text.Trim()); 
     post.PostItems.Add(TextParam09.Text.Trim(), TextValue09.Text.Trim()); 
     post.PostItems.Add(TextParam10.Text.Trim(), TextValue10.Text.Trim()); 
     post.PostItems.Add(TextParam11.Text.Trim(), TextValue11.Text.Trim()); 
     post.PostItems.Add(TextParam12.Text.Trim(), TextValue12.Text.Trim()); 
     post.Type = PostTypeEnum.Post; 

     return await post.Post(); 
    } 

行爲是不是很期待。該生產線TextResponse.Text += Task.Factory.StartNew(() => PostSomeData().Wait());颼颼,通過和我也不例外,這裏是生成的字符串:

Begining ... System.Threading.Tasks.Task 函數來完成! 功能已終止!

現在,如果我使用POST,我會在上面得到一個異常。挖掘到異常顯示500內部服務器錯誤

但是,如果我使用GET,沒有任何反應。沒有例外,只有最後的結果。

我在PostSubmitter類中做錯了什麼?

這裏是UI投籃paramaeters: UI Screen Shot http://img268.imageshack.us/img268/1010/restclient2.png

問候。

更新#1 我也修改了UI上的點擊事件。但是

  • 它只適用於PostType爲GET。 POST不起作用。
  • 的UI 掛起而操作持續

的修改:

private async void ButtonSubmit_Click(object sender, EventArgs e) { 
     ButtonReset.Enabled = false; 
     TextResponse.Text = String.Empty; 
     TextResponse.Text += "Begining..." + Environment.NewLine; 

     try { 
      TextResponse.Text += await PostSomeData(); 
      TextResponse.Text += Environment.NewLine; 
      TextResponse.Text += "Function Done!" + Environment.NewLine; 
     } 
     catch (Exception ex) { 
      TextResponse.Text += "Exception!" + Environment.NewLine + "Message: " + ex.Message + Environment.NewLine; 
     } 
     finally { 
      ButtonReset.Enabled = true; 
      TextResponse.Text += "Function Ended!"; 
     } 
    } 
+0

僅供參考'm_'變量前綴在.NET命名中被認爲是錯誤的。 –

+1

^完全同意。一些初中寫道。一旦我理清了這一點,我就會解僱他。他歡快地回家說「一切都是完成的」...... n00b。 – DoomerDGR8

+0

我想知道爲什麼用戶界面掛着? – DoomerDGR8

回答

3

您的代碼只是部分異步;仔細看看PostData

尤其ReadToEnd必須是異步的:

private async Task<String> PostData(string url, string postData) 
{ 
    HttpWebRequest request = null; 
    if (m_type == PostTypeEnum.Post) 
    { 
    Uri uri = new Uri(url); 
    request = (HttpWebRequest)WebRequest.Create(uri); 
    request.Method = "POST"; 
    request.ContentType = "application/x-www-form-urlencoded"; 
    request.ContentLength = postData.Length; 
    using (Stream writeStream = await request.GetRequestStreamAsync()) 
    { 
     UTF8Encoding encoding = new UTF8Encoding(); 
     byte[] bytes = encoding.GetBytes(postData); 
     await writeStream.WriteAsync(bytes, 0, bytes.Length); 
    } 
    } 
    else 
    { 
    Uri uri = new Uri(url + "?" + postData); 
    request = (HttpWebRequest)WebRequest.Create(uri); 
    request.Method = "GET"; 
    } 

    using (HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync()) 
    using (Stream responseStream = response.GetResponseStream()) 
    using (StreamReader readStream = new StreamReader(responseStream, Encoding.UTF8)) 
    { 
    return await readStream.ReadToEndAsync(); 
    } 
} 

這是除了使事件處理程序異步的,正如其他人提及。

+0

好的。似乎所有東西都正在工作,包括POST方法。謝謝。 – DoomerDGR8

1

試着這麼做:

private async void ButtonSubmit_Click(object sender, EventArgs e) { 

     ButtonReset.Enabled = false; 
     TextResponse.Text = String.Empty; 
     TextResponse.Text += "Begining..." + Environment.NewLine; 

     TextResponse.Text += await PostSomeData(); 
     TextResponse.Text += Environment.NewLine; 
     TextResponse.Text += "Function Done!" + Environment.NewLine; 

} 
+0

那麼,那確實解決了它。但是,只有類型是GET。此外,用戶界面凍結。我不能讓界面凍結...有什麼建議嗎? – DoomerDGR8

1

您需要使用asyncawait關鍵字在你的客戶。更改這2行,你應該很好:

private void ButtonSubmit_Click(object sender, EventArgs e) { 
=> 
private async void ButtonSubmit_Click(object sender, EventArgs e) { 

TextResponse.Text += Task.Factory.StartNew(() => PostSomeData().Wait()); 
=> 
TextResponse.Text += await PostSomeData(); 
相關問題