Waiting for responses to asynchronous HTTP request

2019-06-13 04:33发布

I'm developing a plugin to Windows Forms app that diplays locations of terminals on the map (in WebBrowser control). The case is following:

  1. User clicks the button (calls the plugin);
  2. Async HTTP requests are created (determination of coordinates of terminals);
  3. As all the responses are recieved - the map should be diplayed to user.

I wrote the code:

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 = ...

It blocks UI thread as I have to wait until I get all the responses (coordinates) before I can display the map. I want to know how I can avoid that (without making a synchronous http requests)?

P.S. I know how to do it with async/await but cannot use them - I have to use .NET 4.0 and VS2010 - Microsoft.Bcl.Async cannot help).

3条回答
别忘想泡老子
2楼-- · 2019-06-13 04:50

You could use System.Threading.ThreadPool.QueueUserWorkItem to start your code which will run it on a separate thread to the UI but remember that you'll need to invoke webBrowser1.DocumentText = ... as you'll get an exception if you won't. Hope this helps.

查看更多
再贱就再见
3楼-- · 2019-06-13 04:54

As far as I can see you are struck with it how to do it in c# 4.0.

It is not that hard, keep in mind people used to do these kind of job in .Net 1.0 also, even before that :)

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

Am I missing something?

查看更多
Juvenile、少年°
4楼-- · 2019-06-13 05:05

The BackgroundWorker class provides a casually easy way to perform work away from the UI thread. Perform your work in the .DoWork event handler, and upon completion, the UI thread is invoked to perform the .RunWorkerComplete eventhandler, in which you can update your UI with the map.

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
  }
}
查看更多
登录 后发表回答