WPF, Silverlight, WP7 and the Async CTP

Print Content | More

In the past days I had a chance to give an eye to these future feature of the .NET framework and I have to say I really love it. It allows you to write code that have to run asynchronously or in sequence (continuations) in a very simple and intuitive way.

If you know the basic principles of asynchronous programming the learning curve is quite smooth and fast (it took half a day to me to read up some documentation and start coding my first experiments)

I will not go into the in-depth of the feature, because the official documentation is good and easy to read; at this link you can find all the references and the tutorials to start with: Visual Studio Asynchronous Programming.

The CTP can be used with any .NET platform: desktop framework, Silverlight or WP7; this is good so you can experiment with your favorite environment.

Asynchronous operations are methods and other function members that may have most of their execution take place after they return. In .NET the recommended pattern for asynchronous operations is for them to return a task which represents the ongoing operation and allows waiting for its eventual outcome.

Basically after you install the CTP you’ll have access to two new language keywords and some support classes:

  • async: marks a function as an asynchronous function, it must return void, Task, Task<T> types; inside an async function you can use await expression to wait on ongoing tasks, in other words you flow of execution for the current function stops until the Task you requested to wait for ends (the programming language is responsible for setting up and handling the continuations).
  • await: causes the flow of execution to stop for the current function until the Task (or Task<T>) for which it’s called end, then the execution proceed to the previous calling point.
  • Task: it represents an asynchronous operation and exposes all the needed information to check its current execution state or to await until the execution ends.
  • TaskEx: exposes some utility and helpers function that allows us to execute asynchronous code in different threads or await for multiple tasks termination.

As you’ll see in a while using these classes is easy, and the framework itself will take care of the dirty work of generating the state machine to handle your sequence of operation; however always keep in mind this: asynchronous programming doesn’t mean ‘background threads’ all the time.

Enough talking let’s see some code in action in my WP7 app ‘All About PrimordialCode’, I’ll start by showing you some traditional async code I had there, this was the starting RssClient class that was used to retrieve the rss feeds:

public class RssClient
{
	private readonly string _rssUrl;
	private readonly object _control;

	public delegate void ItemsReceivedDelegate(RssClient client, IList<FeedItem> items, Object control);
	public event ItemsReceivedDelegate ItemsReceived;

	public RssClient(string rssUrl, object control)
	{
		_rssUrl = rssUrl;
		_control = control;
	}

	public void LoadItems()
	{
		var request = (HttpWebRequest)WebRequest.Create(_rssUrl);
		request.BeginGetResponse(ResponseCallback, request);
	}

	void ResponseCallback(IAsyncResult result)
	{
		var request = (HttpWebRequest)result.AsyncState;

		WebResponse response;
		try
		{
			response = request.EndGetResponse(result);
		}
		catch (Exception)
		{
			if (ItemsReceived != null)
				ItemsReceived(this, null, _control);
			return;
		}

		var stream = response.GetResponseStream();
		var reader = XmlReader.Create(stream);
		var items = new List<FeedItem>(50);

		FeedItem item = null;
		var pointerMoved = false;

		while (!reader.EOF)
		{
		
//			...
//			boring code to read items and add them to the 'items' list
//			...

		if (ItemsReceived != null)
			ItemsReceived(this, items, _control);
	}
}

In this code you will see a callback that is scheduled to be executed when we start getting the data stream (line 18) and an event (lines 51-52) that will be raised to give the control back to the calling application to let the rest of the processing go on (continuation). You will also notice that this class will also accept on his constructor the control that will be filled with the returned data.

This is how this class was used:

//...
var rssClient = new RssClient("http://twitter.com/statuses/...", listctrl); 
rssClient.ItemsReceived += ItemsReceived;
rssClient.LoadItems();
ShowProgressBar(true);
//...
void ItemsReceived(RssClient client, IList<FeedItem> items, object control)
{
	Dispatcher.BeginInvoke(delegate
	{
		if (items != null)
		{
			((ItemsControl)control).ItemsSource = items;
		}
		else
		{
			if (((ItemsControl)control).Items.Count == 1)
			{
				FeedItem fi = new FeedItem();
				fi.Title = "No connection";
				fi.Description = "";

				List<FeedItem> lfi = new List<FeedItem>();
				lfi.Add(fi);

				((ItemsControl)control).ItemsSource = lfi;
			}
		}
		ShowProgressBar(false);
	});
}

We’ve added an event handler and we used a Dispatcher.BeginInvoke() to be sure to execute this function on the correct UI thread (to avoid the cross thread exception when updating a control from a background thread).

This is more or less how we do these things now, let’s see now how it will change starting from the RssClass:

public class RssClientAsync
{
	private readonly string _rssUrl;
	
	public RssClientAsync(string rssUrl)
	{
		_rssUrl = rssUrl;
	}

	public async Task<IList<FeedItem>> LoadItemsAsync()
	{
		var client = new WebClient();

		// async call to retrieve the data (in the same thread)
		string data = await client.DownloadStringTaskAsync(_rssUrl);

		if (string.IsNullOrEmpty(data))
			return null;

		// i wanna run the rest of the processing in a background thread
		return await TaskEx.Run(delegate
		{
			var items = XDocument.Parse(data).Descendants("item")
				.Select(e => new FeedItem()
				{
					Title = (string)e.Element("title"),
					Description = Regex.Replace((string)e.Element("description"), @"<(.|\n)*?>", " "),
					Link = ParseLink(e),
					PublishDate = ParseDate((string)e.Element("pubDate"))
				});
			return items.ToList();
		});
	}
	
	// some parsing functions...
}

This is going to be interesting, first off I removed the reference to the control and the ItemsReceived event, I will not need them anymore.

Line 10: I marked the function as async and I changed the return type of the function to Task<IList<FeedItems>>, which means that WHEN this function will end it will returns me the whole list of items parsed from the rss stream.

Line 15: here we take advantage of some extension that the CTP adds to the WebClient class, the DownloadStringTaskAsync will return a Task<string> object we can wait on with the await keyword. The language will build a state machine to wait for this function to end, then the execution will proceed with...

Line 21: we have the whole rss stream read inside our ‘data’ string, it’s time to process it and I choose to force it t execute in a background thread (TaskEx.Run() will force the execution of the delegate in a background thread and it will return a Task object we can wait on), once again we used the await keyword to let the language know that we want to wait for the task to end before going on with the original function.

Awesome! we’ve wrote asynchronous code like it was synchronous without altering the ‘flow’ or jumping back and forth following events and callbacks...but wait we’ve not done, let’s see how we use this piece of beauty:

private async void TwitterRefreshClick(object sender, RoutedEventArgs e)
{
	var twiClient = new RssClientAsync("http://twitter.com/statuses/..."); 
	ShowProgressBar(true);
	var items = await twiClient.LoadItemsAsync();

	if (items.Count != 0)
	{
		Twitter.ItemsSource = items;
	}
	else
	{
		FeedItem fi = new FeedItem();
		fi.Title = "No connection";
		fi.Description = "";

		List<FeedItem> lfi = new List<FeedItem>();
		lfi.Add(fi);

		Twitter.ItemsSource = lfi;
	}

	ShowProgressBar(false);
}

Line 01: we need to mark the function as async, because we’ll need to use asynchronous operation inside it.

Line 03-04: creates and instance of the client class and start a progress bar animation.

Line 05: we call and ‘await’ for the LoadItemsAsync() function to complete Open-mouthed smile, once it’s done the control returns to the rest of the function that..

Line 07-23: binds the result to the list control (same code we had inside the event handler before) and stops the progress bar animation.

Once again the flow of execution is perfectly clear and the code is extremely easy to read.

In the end I have to admit that this CTP really impresses me, it makes writing asynchronous code a breeze in a wide range of scenarios, here I used a WP7 project as example, but it’s really the same in any other platform, so just go there and download this CTP to try it. I really can’t wait to use it in ‘real’ production code.

Oh well...actually I do...in the next days I’ll push to the WP7 marketplace another version of ‘All About PrimordialCode’ that uses the Async CTP for these kind of processing.



WPF, Silverlight, WP7, Async

1 comments

Related Post

  1. #1 da John Parr - Monday May 2011 alle 01:43

    Impressive Stuff..

All fields are required and you must provide valid data in order to be able to comment on this post.


(will not be published)
(es: http://www.mysite.com)