2

我正在使用 WebRequest 进行简单的请求,并且应用程序只是挂起,直到响应返回。我该如何解决?

我已经阅读了很多主题,他们都说要使用线程。我不知道如何使用它们;谁能提供以下不挂起用户界面的示例?

private string SimpleRequest(String url)
{
    WebRequest request = WebRequest.Create(url);
    WebResponse response = request.GetResponse();
    Stream stream = response.GetResponseStream();
    StreamReader reader = new StreamReader(stream);
    string result = reader.ReadToEnd();
    stream.Dispose();
    reader.Dispose();
    return result;
}

private void button1_Click(object sender, EventArgs e)
{
    String googleHtml = simpleRequest("https://facebook.com");
}

谢谢!

4

4 回答 4

8

如果您使用的是 c# 5.0,那就太容易了

public async void Test1()
{
      WebClient wc = new WebClient();
      richTextBox1.Text =  await wc.DownloadStringTaskAsync("https://facebook.com");
}

您可以将您的方法转换awaitable

private Task<string> simpleRequest(String url)
{
    return Task.Factory.StartNew(() =>
        {
            WebRequest request = WebRequest.Create(url);
            WebResponse response = request.GetResponse();
            Stream stream = response.GetResponseStream();
            StreamReader reader = new StreamReader(stream);
            string result = reader.ReadToEnd();
            stream.Dispose();
            reader.Dispose();
            return result;
        });
}

并称为

public async void Test2()
{
      richTextBox1.Text =  await simpleRequest("https://facebook.com");
}

对于较低版本的 C#,请参阅其他答案。

于 2012-08-26T16:39:58.927 回答
3

您正在主 UI 线程上进行网络访问。UI 有一个循环和更新 UI 的主线程。如果您在该线程上进行网络访问,UI 将不会更新,并且它会显示为挂起,直到您的方法返回并且循环可以继续。

考虑在后台线程上做你的工作。在 .net 中实现此目的的一种简单方法是 BackgroundWorker 类。

官方文档有一个很好的用法示例:

http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

BackgroundWorker 类允许您在单独的专用线程上运行操作。下载和数据库事务等耗时的操作可能会导致您的用户界面 (UI) 在运行时似乎停止响应。当您需要响应式 UI 并且面临与此类操作相关的长时间延迟时,BackgroundWorker 类提供了一种方便的解决方案。

于 2012-08-26T16:27:08.470 回答
3

您可以使用 aBackgroundWorker来使用除 UI 线程之外的另一个线程。这是一个示例

您还可以取消或显示进度:

public partial class fmMain : Form
{
    private void btnrunBackgroundWorker_Click( object sender, EventArgs e )
    {
        // Create a background worker
        BackgroundWorker bw = new BackgroundWorker();
        bw.DoWork += new DoWorkEventHandler( bw_DoWork );

        // run in another thread
        bw.RunWorkerAsync();     
    }

    private void bw_DoWork( object sender, DoWorkEventArgs e )
    {
        String facebookHtml = simpleRequest("https://facebook.com");
    }
}
于 2012-08-26T16:30:25.170 回答
2

您应该使用BackgroundWorker,这样您的主 UI 线程就不会挂起!

private void button1_Click(object sender, EventArgs e)
{
    backgroundWorker1.RunWorkerAsync("https://facebook.com"); // start async operation
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    e.Result = simpleRequest(e.Argument.ToString()); // set result in async operation
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Error == null)
    {
        // show result here
        // or access/manage result here
        MessageBox.Show(e.Result.ToString());
    }
    else
    {
        // manage/show error
        MessageBox.Show(e.Error.Message);
    }
}
private String simpleRequest(String url)
{
     // your code goes here
}

您也可以实现backgroundWorker1_ProgressChanged,以便用户可以看到加载网站的进度。(旁注:有关ProgressChanged 和 Context的详细信息,请参阅此问题)

于 2012-08-26T16:41:14.373 回答