等待没有异步/等待的异步HTTP请求的响应

时间:2014-01-20 08:56:55

标签: c# .net winforms asynchronous

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

  1. 用户点击按钮(调用插件);
  2. 创建异步HTTP请求(确定终端的坐标);
  3. 所有收到回复时 - 应将地图显示给用户。
  4. 我写了代码:

    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无法帮助。)

3 个答案:

答案 0 :(得分: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 );

我错过了什么吗?

答案 1 :(得分:0)

您可以使用System.Threading.ThreadPool.QueueUserWorkItem启动您的代码,该代码将在与UI的单独线程上运行,但请记住,您需要调用webBrowser1.DocumentText = ...,因为如果您赢了将获得异常“T。 希望这会有所帮助。

答案 2 :(得分:0)

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