Monthly Archives: February 2013

Making Multiple Service Calls Asynchronously in a Windows 8 Modern UI App

Although it’s taken me a while to get my head around the asynchronous service calls with the await and async keywords, I think they are a great addition to the API. Simply adding the await keyword to an auto generated service proxy makes the service call run in a separate thread whilst the UI can continue it’s work as normal.

However, what if you load a page which makes multiple asynchronous calls to different services? Simply adding the await keyword to a method within the OnNavigatedTo or LoadState Page methods will mean that although the UI thread will still happily run in the background, each service call will be made sequentially which isn’t the most efficient way of doing it. Ideally we want all the service calls to be made at the same time to minimise the time it takes for the data to load.

The solution I found was to call the method without the await keyword and return the Task<> object. Then by using the ContinueWith method of the Task I could capture the results within a separate method as and when the service call finished. This way all the tasks are fired at the same time but the results are processed only when the method returned a result. Note that the results have to be brought back into the UI thread by using the Dispatcher object held within the page otherwise I got a message saying “the application called an interface that was marshalled for a different thread”.

protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
{
	// Instantiate our helper class which makes all the service calls
	PersonServiceHelper helper = new PersonServiceHelper();
	// we could just simply run await() but because we are making multiple service calls, lets run them all asynchronously
	Task < MyCompany.Windows8.App.PersonHelper.PersonService.GetEmploymentDetailsResponse1 > t1 = 
		helper.getEmploymentDetails(PersonSearchResult.PACID);
	t1.ContinueWith(ReadEmploymentResults);
	
	Task<MyCompany.Windows8.App.PersonHelper.PersonService.GetWorkPhonesResponse1> t3 =
		helper.getWorkPhoneDetails(PersonSearchResult.PACID);
	t3.ContinueWith(ReadWorkPhonesResults);
	
	Task<MyCompany.Windows8.App.PersonHelper.PersonService.GetDirectoryDetailsResponse1> t4 =
		helper.getDirectoryDetails(PersonSearchResult.PACID);
	t4.ContinueWith(ReadDirectoryDetailsResults);
   
}

private async void ReadEmploymentResults(Task<MyCompany.Windows8.App.PersonHelper.PersonService.GetEmploymentDetailsResponse1> t)
{
	await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
	{
		this.DefaultViewModel["PersonEmployment"] = t.Result.GetEmploymentDetailsResponse.GetEmploymentDetailsResult;
	});
}


private async void ReadWorkPhonesResults(Task<MyCompany.Windows8.App.PersonHelper.PersonService.GetWorkPhonesResponse1> t)
{
	await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
	{
		this.DefaultViewModel["PersonWorkPhones"] = t.Result.GetWorkPhonesResponse.GetWorkPhonesResult.Phones;

	});
}

private async void ReadDirectoryDetailsResults(Task<MyCompany.Windows8.App.PersonHelper.PersonService.GetDirectoryDetailsResponse1> t)
{
	await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
	{
		this.DefaultViewModel["PersonDirectoryDetails"] = t.Result.GetDirectoryDetailsResponse.GetDirectoryDetailsResult;
	});
}