简体   繁体   中英

Waiting for responses to asynchronous HTTP requests without async/await

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)?

PS 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).

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?

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM