Asycnhronous Service Calls with Coroutines

Pete Brown just published a great blog post about calling WCF or Web services asynchronously, so I had to pull down his sample code and make it work with MVVM Light and the coroutine support from MadProps.MvvmLight.

The first thing I did was remove the "Click" event handler from his CallService button, and instead define a command for it in the code-behind. Note that ordinarily this code would be in a ViewModel and you'd bind the command to the button, but I was just hacking away at sample code so this was nice and quick:

public MainWindow()
{
    InitializeComponent();

    var processor = new ActivityProcessor();
    CallService.Command = processor.CreateCommand(CallServiceExecuted);
}

Then I defined the CallServiceExecuted method:

IEnumerable<IActivity> CallServiceExecuted()
{
    var callService = new CallServiceActivity();
    yield return callService;

    CustomerList.ItemsSource = callService.Customers;
}

And lastly an activity to do the actual call, using Pete's callback code:

public class CallServiceActivity : ActivityBase
{
    void ResponseCallback(IAsyncResult asyncResult)
    {
        CustomerRequestState asyncState = asyncResult.AsyncState as CustomerRequestState;

        Customers = asyncState.Client.EndGetCustomers(asyncResult);

        RaiseCompleted();
    }

    public Customer[] Customers { get; private set; }

    public override void Execute(ActivityContext context)
    {
        var client = new Services.CustomerServiceClient();

        CustomerRequestState requestState = new CustomerRequestState();
        requestState.Client = client;

        client.BeginGetCustomers(new AsyncCallback(ResponseCallback), requestState);
    }
}

The activity itself could've been defined in any number of ways, but it was simple enough to steal Pete's code and write it in a similar fashion.

Note that there's no need to synchronize the call back to the UI thread, because the ActivitiyProcessor class handles that for you via the default dispatcher. If you hide your activity away in a separate file somewhere, the actual logic looks very sequential and easy to read. Imagine how much less complex this would be if you had a few asynchronous calls to make, one after the other!

Update

For completeness, here's another, simpler way to define the CallServiceActivity class:

public class CallServiceActivity : ActivityBase
{
    public Customer[] Customers { get; private set; }

    public override void Execute(ActivityContext context)
    {
        var client = new Services.CustomerServiceClient();

        client.GetCustomersCompleted += (s, ev) =>
            {
                Customers = ev.Result;
                RaiseCompleted();
            };

        client.GetCustomersAsync();
    }
}
mvvm wcf coroutines
Posted by: Matt Hamilton
Last revised: 20 Apr, 2014 09:43 PM History

Trackbacks

Comments

Craigology
Craigology
20 Feb, 2011 09:46 PM

Hi Matt,

Great series on coroutines in MVVM.

Wondering what's your approach, if any, for unit testing coroutines + async?

Where would you put your seams amongst this to facilitate testability?

21 Feb, 2011 04:41 AM

Hi Craig,

I haven't actually tried testing yet, but I think it should be a snap. Since your method returns an IEnumerable<IActivity> you can just call it and check the results. Something like:

var activities = subjectUnderTest.CallServiceExecuted().ToList();
Assert.IsOfType<CallServiceActivity>(activities[0]);

Obviously testing the activities themselves would be a separate process.

No new comments are allowed on this post.