PostSubmitter 的异步 CTP

发布于 2024-12-10 13:10:55 字数 9971 浏览 0 评论 0原文

我正在尝试使用 Async CTP 构建 REST 客户端。我是 CTP 的新手,因此,在浏览了互联网上的许多示例之后,我得到了一个专门用于发布(GET 或 POST)的类。这是到目前为止的课程:

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 ... 系统.线程.任务.任务 功能完成! 功能结束!

现在,如果我使用 POST,我会在上述之后收到异常。深入研究异常发现500内部服务器错误

但是,如果我使用GET,则什么也不会发生。没有例外,最终结果相同。

我在 PostSubmitter 类中做错了什么吗?

这是带有参数的 UI 截图:

问候。

更新#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!";
        }
    }

I'm trying to build a REST Client usign Async CTP. I'm new to the CTP and hence, afetr going through a number of examples on the internet, I got a clas built for just posting (GET or POST). Here is the class so far:

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));
        }

    }

}

And this is how I'm using it:

    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();
    }

The behaviour is not quite as expected. The line TextResponse.Text += Task.Factory.StartNew(() => PostSomeData().Wait()); whiz-by and I get no exceptions and here is the resulting string:

Begining...
System.Threading.Tasks.Task
Function Done!
Function Ended!

Now, if I'm using a POST, I get an exception after the above. Digging into the exception reveals a 500 Internal Server Error

However, if i'm using GET, nothing happens. No exception and just the same final result.

Am I doing something wrong in the PostSubmitter Class?

Here is the UI shot with the paramaeters:
UI Screen Shot

Regards.

Update #1
I have modified the click event on the UI as well. However

  • It only works if the PostType is GET. POST is not working.
  • The UI hangs while the operation lasts

The modifications:

    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!";
        }
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

北渚 2024-12-17 13:10:55

您的代码只是部分异步的;仔细看看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();
  }
}

正如其他人提到的那样,这是除了使事件处理程序异步之外的补充。

Your code is only partially asynchronous; take a good look at PostData.

In particular, ReadToEnd needs to be asynchronous:

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();
  }
}

This is in addition to making your event handler asynchronous, as others have mentioned.

挖个坑埋了你 2024-12-17 13:10:55

尝试类似的方法:

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;

}

Try something like:

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;

}
遗失的美好 2024-12-17 13:10:55

您需要在客户端中使用 asyncawait 关键字。改变这两行,你应该就好了:

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();

You need to use the async and await keywords in your client. Change these 2 lines and you should be good:

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();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文