【问题标题】:HttpWebRequest.BeginGetResponseHttpWebRequest.BeginGetResponse
【发布时间】:2012-02-21 07:32:12
【问题描述】:

我需要向网络资源发出异步请求并使用此页面 (link to full example) 中的示例:

HttpWebRequest myHttpWebRequest= (HttpWebRequest)WebRequest.Create("http://www.contoso.com");
RequestState myRequestState = new RequestState();  
myRequestState.request = myHttpWebRequest;
// Start the asynchronous request.
IAsyncResult result=
        (IAsyncResult) myHttpWebRequest.BeginGetResponse(new AsyncCallback(RespCallback),myRequestState);

但是当我测试应用程序时,此代码最后一行的执行冻结(2-3 秒)(我可以使用调试器观看它)。

为什么?是我的错误还是函数的标准行为?

【问题讨论】:

    标签: c# .net wpf asynchronous httpwebrequest


    【解决方案1】:

    你可以试试,我相信这样更好

    private void StartWebRequest(string url)
    {
       HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
       request.BeginGetResponse(new AsyncCallback(FinishWebRequest), request);
    }
    
    private void FinishWebRequest(IAsyncResult result)
    {
       HttpWebResponse response = (result.AsyncState as HttpWebRequest).EndGetResponse(result) as HttpWebResponse;
    }
    

    由于 textbox'value 的 chross 线程,但这是 wpf 应用程序,我将重新标记它,顺便说一句,您可以使用 webclient 之类的

     private void tbWord_TextChanged(object sender, TextChangedEventArgs e)
        {
            WebClient wc = new WebClient();
            wc.DownloadStringCompleted += HttpsCompleted;
            wc.DownloadStringAsync(new Uri("http://en.wikipedia.org/w/api.php?action=opensearch&search=" + tbWord.Text)); 
        }
        private void HttpsCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            if (e.Error == null)
            {
    
                 //do what ever 
                 //with using e.Result
            }
        } 
    

    【讨论】:

    • 第二种方法中的 IAsyncResult 参数是什么?调用 request.BeginGetResponse() 的结果?
    • 正如我所见,它并没有改变任何东西。这是完整代码pastebin.com/trvq1qza。 GUI 窗口在第 18 行冻结。
    • 在我的窗口中,主窗口冻结,我无法移动窗口,也看不到鼠标光标悬停在窗口上:(
    • @demas 是 wpf 应用程序吗?如果不是在互联网上寻找跨线程
    • 如何从FinishWebRequest得到HttpWebResponse
    【解决方案2】:

    响应发生在单独的线程上。 Winforms 不是多线程安全的,因此您将不得不在与表单相同的线程上调度调用。

    您可以使用窗口的内部消息循环来执行此操作。幸运的是,.NET 提供了一种方法来做到这一点。您可以使用控件的 Invoke 或 BeginInvoke 方法来执行此操作。前者阻塞当前线程,直到 UI 线程完成调用的方法。后者异步执行此操作。除非有清理工作要做,否则您可以使用后者来“一劳永逸”

    为此,您需要创建一个由 BeginInvoke 调用的方法,并且您需要一个委托来指向该方法。

    有关详细信息,请参阅 MSDN 中的 Control.Invoke 和 Control.BeginInvoke。

    此链接有一个示例:https://msdn.microsoft.com/en-us/library/zyzhdc6b(v=vs.110).aspx

    更新:当我浏览我的个人资料时,因为我忘记了我在这里有一个帐户 - 我注意到了这一点,我应该补充一下:任何超过 3.5 或当他们显着改变这里的异步线程模型时都超出了我的驾驶室。我是专业人士,虽然我仍然热爱这项手艺,但我并没有追随每一个进步。我可以告诉您的是,这应该适用于所有版本的 .NET,但如果仍然存在,它可能不是性能 4.0 及更高版本或 Mono/Winforms 仿真的绝对顶峰。从好的方面来说,任何攻击在服务器应用程序之外通常都不会是坏事,即使在线程池正在执行其工作的情况下也是如此。所以在大多数情况下不要在这里集中优化工作,它更有可能在你看到运行 C# 移动包之类的“精简”平台上工作,尽管我必须确定并且大多数不运行 winforms 但是一些自旋消息循环,这也适用于那里。基本上,在最后一种情况下,这不是最新平台的“最佳答案”。但在正确的情况下它可能更便携。如果这有助于一个人避免犯设计错误,那么我花时间写这篇文章是值得的。 =)

    【讨论】:

      【解决方案3】:

      您可以在 DoWork 中使用 BackgroundWorker 添加完成所有工作

      【讨论】:

        【解决方案4】:

        这是标准行为。

        来自documentation on HttpWebRequest.BeginGetResponse Method

        BeginGetResponse 方法需要在此方法变为异步之前完成一些同步设置任务(例如 DNS 解析、代理检测和 TCP 套接字连接)。 [...] 在引发错误异常或方法成功之前,完成初始同步设置任务可能需要相当长的时间(长达几分钟,具体取决于网络设置)。

        为避免等待设置,您可以使用 HttpWebRequest.BeginGetRequestStream Method 但请注意:

        您的应用程序不能为特定请求混合使用同步和异步方法。如果调用 BeginGetRequestStream 方法,则必须使用 BeginGetResponse 方法来检索响应。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-05-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多