1

I have a web page that has a form to add devices.

When a user adds a device, the device is registered in 4 different places. Since each of these 4 registrations takes time I decided to use asynchronous calls.

So, when the user clicks the save button an AJAx request is fired to the server and invokes the "Save" method. The "Save" method has a loop with an asynchronous call to the "Register" method, like this:

public delegate bool DeviceControllerAsync(...);

public static string Save(...)
{
    //Get all active controllers
    List<Controller> lstControllers = Controller.Get();
    foreach (Controller controller in lstControllers)
    {
        // Invoke asynchronous write method
        DeviceControllerAsync caller = new DeviceControllerAsync(ArubaBL.RegisterDevice);

        // Initiate the asychronous call.
        IAsyncResult result = caller.BeginInvoke(..., null, null);
    }
    return GetRegisteredDevices();
}

The problem here is that the "GetRegisteredDevices" call is pointless because the async methods haven't finished yet and there will be no devices to return. Also, I can't update the UI when these actions finish because the main method already returned to the UI.

(I'm ignoring the case here if the user moves the another page right after clicking the "Save" button.)

So, is there a way for me to know when all async calls finished and then invoke a method that will update the UI?

Liran Friedman
  • 4,027
  • 13
  • 53
  • 96
  • 1
    Can you migrate to TPL instead of the old style begin/endinvoke? – caesay Oct 25 '15 at 06:35
  • [this](http://stackoverflow.com/questions/26069487/async-and-await-with-for-loop) might help – LiranBo Oct 25 '15 at 06:36
  • I could migrate to TPL if I knew what it is... What is TPL ??? – Liran Friedman Oct 25 '15 at 06:38
  • TPL: a simple google search away https://msdn.microsoft.com/en-us/library/dd537609(v=vs.110).aspx – caesay Oct 25 '15 at 06:39
  • I think [async/await](https://msdn.microsoft.com/en-us/library/hh191443.aspx) would be easier than basic TPL... Please update tags on your post to specify what framework you use (anything but plain ASP.Net would be easy to use async/await) – Alexei Levenkov Oct 25 '15 at 06:41
  • *The problem here is that the "GetRegisteredDevices" call is pointless because the async methods haven't finished yet and there will be no devices to return.* Currently, you block the async invocation with the call to `EndInvoke` right after `BeginInvoke`. Any reason you're doing it this way? – Yuval Itzchakov Oct 25 '15 at 07:29
  • You are correct, this code was originally remarked, and I deleted it now. – Liran Friedman Oct 25 '15 at 07:32

1 Answers1

0

A simplified example of what this might look like using the TPL library and the async/await keywords.

public static async string Save(...)
{
    //Get all active controllers
    List<Controller> lstControllers = Controller.Get();

    //Create a task object for each async task
    List<Task<returnValueType>> controllerTasks = lstControllers.Select(controller=>{
        DeviceControllerAsync caller = new DeviceControllerAsync(ArubaBL.RegisterDevice);
        return Task.Factory.FromAsync<returnValueType>(caller.BeginInvoke, caller.EndInvoke, null);
    }).ToList();

    // wait for tasks to complete (asynchronously using await)
    await Task.WhenAll(controllerTasks);

    //Do something with the result value from the tasks within controllerTasks
}
caesay
  • 16,932
  • 15
  • 95
  • 160
  • Any idea why this code does not compile? `'System.Threading.Tasks.Task' does not contain a definition for 'WhenAll'` – Liran Friedman Oct 25 '15 at 07:10
  • @Liran Yes, `Task.WhenAll` isn't available on .NET 4. Try the [`Microsoft.Bcl.Async`](https://www.nuget.org/packages/Microsoft.Bcl.Async/) package from NuGet. – Yuval Itzchakov Oct 25 '15 at 07:29
  • I'm using Visual Studio 2010. Unfortunately: "This package is not supported in Visual Studio 2010, and is only required for projects targeting. NET Framework 4.5, Windows 8, Windows Phone Silverlight 8, or Windows Phone 8.1 when consuming a library that uses this package. " – Liran Friedman Oct 25 '15 at 07:35
  • Can I use `Task.Factory.ContinueWhenAll` instead ? – Liran Friedman Oct 25 '15 at 07:45
  • @Liran `ContinueWhenAll` will not synchronously wait. You can use `Task.WaitAll`, which does that exactly. Note it will block the calling thread until all tasks complete. – Yuval Itzchakov Oct 25 '15 at 08:55
  • So it will also block the UI as well, and the main reason I used async call is not to block the UI... – Liran Friedman Oct 25 '15 at 09:07