【问题标题】:Waiting for responses to asynchronous HTTP requests without async/await在没有 async/await 的情况下等待对异步 HTTP 请求的响应
【发布时间】:2014-01-20 08:56:54
【问题描述】:

我正在为 Windows 窗体应用程序开发一个插件,用于在地图上显示终端的位置(在 WebBrowser 控件中)。案例如下:

  1. 用户点击按钮(调用插件);
  2. 创建异步 HTTP 请求(确定终端坐标);
  3. 所有都收到响应 - 应向用户显示地图。

我写了代码:

foreach (var terminal in terminals)
{

    var webRequest = (HttpWebRequest)WebRequest.Create(GeoCoder.GeoCodeUrl + terminal.Address);
    var taskResp = Task.Factory.FromAsync<WebResponse>(webRequest.BeginGetResponse,
                                                       webRequest.EndGetResponse,
                                                       terminal.Id);
    var taskResult = taskResp.ContinueWith(task =>
    {
        // Parse the response
    });
    runningTasks.Add(taskResult);
}
Task.WaitAll(runningTasks.ToArray()); // UI Thread blocks here!
webBrowser1.DocumentText = ...

它会阻塞 UI 线程,因为我必须等到获得所有响应(坐标)才能显示地图。我想知道如何避免这种情况(不发出同步 http 请求)?

P.S.我知道如何使用 async/await 但不能使用它们 - 我必须使用 .NET 4.0 和 VS2010 - Microsoft.Bcl.Async 无能为力。

【问题讨论】:

    标签: c# .net winforms asynchronous


    【解决方案1】:

    据我所知,您对如何在 c# 4.0 中执行此操作感到震惊。

    这并不难,记住人们曾经在 .Net 1.0 中也做过这类工作,甚至在此之前 :)

    var uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
    Task.Factory.ContinueWhenAll(runningTasks.ToArray(), antecedents =>
    {
        webBrowser1.DocumentText = ...//This runs in UI thread
    },CancellationToken.None, TaskContinuationOptions.None,uiTaskScheduler );
    

    我错过了什么吗?

    【讨论】:

      【解决方案2】:

      您可以使用System.Threading.ThreadPool.QueueUserWorkItem 来启动您的代码,该代码将在UI 的单独线程上运行它,但请记住,您需要调用webBrowser1.DocumentText = ...,因为如果您不这样做,您会得到一个异常。 希望这会有所帮助。

      【讨论】:

      • 我需要在得到最后一个响应后立即调用webBrowser1.DocumentText = ...。我不明白如何使用ThreadPool.QueueUserWorkItem,请您提供更多详细信息吗?
      【解决方案3】:

      BackgroundWorker 类提供了一种在 UI 线程之外执行工作的简单方法。在 .DoWork 事件处理程序中执行您的工作,完成后,调用 UI 线程来执行 .RunWorkerComplete 事件处理程序,您可以在其中使用地图更新您的 UI。

      class Form1
      {
        private System.ComponentModel.BackgroundWorker bgw;
      
        public Form1()
        {
          bgw = new BackgroundWorker();
          bgw.DoWork += WorkMethod;
          bgw.RunWorkerCompleted += WorkCompleteMethod;
        }
      
        private void Button1_Click(object sender, eventargs e)
        {
           if (!bgw.IsBusy)
           {
             bgw.RunWorkerAsync();
           }
        }
      
        private void WorkMethod(object sender, DoWorkEventArgs e)
        {
          //perform work
          //set result to e.Result
        }
      
        private void WorkCompleteMethod(object sender, RunWorkerCompletedEventArgs e)
        {
          //extract result from eventargs
          //update ui
        }
      }
      

      【讨论】:

        猜你喜欢
        • 2013-07-22
        • 2018-06-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多