Monty’s Gush

Dynamic parallel async requests in MVC

Posted on: May 12, 2011

How to make several asynchronous requests in parallel to the same web service, when the number of such requests is dynamically determined.

Thanks to AsyncControllers, it’s quite easy to make several asynchronous requests in parallel to different web services, and have MVC gather the results.

A well-written example is on MSDN. Briefly, you save the result of each async call into the Parameters collection of the AsyncManager like so:

AsyncManager.Parameters["headlines"] = e.Value;
...
AsyncManager.Parameters["scores"] = e.Value;
...
AsyncManager.Parameters["forecast"] = e.Value;

Your Completed method will then bind to the parameters you have named:

public ActionResult IndexCompleted(
    HeadlinesResult headlines, 
    ScoresResult scores, 
    ForecastResult forecast) { ... }

This is fine if you know how many requests you want to make. But what if you want to make several requests in parallel to the same web service (for example, with slightly different parameters) — but you don’t know in advance how many requests you will need to make?

For example, you might show the weather forecast for as many days into the future as the user requests, up to seven days, with each day requiring a separate request to the forecast service.

In this case you need a dynamically-sized collection of results of the same type, such as a list. Ideally, we want our Completed method to look something like this:

public ActionResult IndexCompleted(List results) { ... }

Fist of fun

However, we don’t know on which threads, or even in what order, this collection will be added to when each of the web service calls complete independently.

The System.Collections.Concurrent namespace gives us a more suitable type to withstand the mutation this collection will have to put up with.

public class ForecastController : AsyncController
{
    public void IndexAsync(ForecastInputModel input)
    {
        var results = new ConcurrentBag<ForecastResult>();

        AsyncManager.Parameters["results"] = results;

        foreach (var request in GetForecastRequests(input))
        {
            AsyncManager.OutstandingOperations.Increment();

            var s = new WeatherService();

            s.GetForecastCompleted += (sender, e) =>
                {
                    results.Add(e.Value); // threadsafe
                    AsyncManager.OutstandingOperations.Decrement();
                };
            
            s.GetForecastAsync(request);
        }
    }

    public ActionResult IndexCompleted(ConcurrentBag<ForecastResult> results)
    {
        ...
    }  
 }

Enjoy what you saw.

kick it on DotNetKicks.com

3 Responses to "Dynamic parallel async requests in MVC"

[…] parallel async requests in MVC https://petemontgomery.wordpress.com/2011/05/12/dynamic-parallel-async-requests-in-mvc/ Thanks to AsyncControllers, it’s quite easy to make several asynchronous requests in parallel to […]

[…] Dynamic parallel async requests in MVC […]

Leave a comment