Geeks With Blogs

@codingbloke
  • codingbloke Blogged: Using the AsyncOperationService with HttpWebRequest. Builds on the previous .NET Async Pattern stuff. http://t.co/B5VLg8a about 1053 days ago
  • codingbloke I haven't blogged in a while but http://t.co/jzEgzME its more on AsyncOperationService. Future posts will show more practical uses. about 1095 days ago
  • codingbloke @Pete_Brown I like "custom" mode, gives me the warm fuzzy feel that I'm in control about 1271 days ago

News
The Coding Bloke An ordinary bloke trying to keep up with the world of programming

In Part 1 I provided the code for the simple asynchronous operation runner.  In this post I’ll put it to some use.

First let me provide a real world scenario so that we have something to demonstrate with.

The Scenario

  • I have a desire to separate into resource dictionaries a common palette of colours from a set of styles that use these colours.  The goal being that I change a pair of colours in one place and all parts of the UI using that pair will use the new colour.
  • There may be multiple resource dictionaries holding styles that reference these colours or even a style that may be BasedOn a style in another dictionary.  I want to put these dictionaries outside of the Xap so that on deployment on a client site these files can be easily edited.
  • I want to allow the client add and remove dictionaries from the set and all this without any necessity for script support server-side.

The Challenges

The scenario presents a few challenges.  I need to download some sort of manifest for the set of dictionary files I need.  Then each dictionary needs to be downloaded and added to the application resources before the next dictionary because subsequent dictionaries may depend on foregoing dictionaries.   This is clearly a synchronous sequence where each step must be completed before the next.   The obvious tool to download these files is WebClient.  Imagine for the moment that WebClient had a synchronous DownloadString method.  The code to complete the scenario could look something like this:-

 

 

Imaginary Code
private void LoadExternalResourcesSync()
{
    WebClient wc = new WebClient();

    string manifestXml = wc.DownloadString(new Uri("External/ResourceManifest.xml", UriKind.Relative));

    XDocument manifest = XDocument.Parse(manifestXml);

    foreach (XElement resourceElem in manifest.Descendants("resource"))
    {
        Uri resourceUri = new Uri(resourceElem.Attribute("source").Value, UriKind.Relative);
        string resourceXaml = wc.DownloadString(resourceUri);

        var resource = XamlReader.Load(resourceXaml) as ResourceDictionary;
        Resources.MergedDictionaries.Add(resource);
    }
}

This looks like a fairly straight forward chunk of code that implements the sequence outlined above.  Sadly there is no such DownloadString method.  We only have DownloadStringAsync and converting the above code to achieve the same result gets real ugly real quick, so much so that I daren’t even present what the code would look like.

The design goal I had in mind for the Asynchronous Operation Runner was to be able to write code that looks likes it is synchronous (therefore not a million miles away from the code above) but would actually work asynchronously.

First order of business then looking at the code above is create an AsyncOperation that performs a DownloadString.  There is no magic here, I can’t actually create a synchronous DownloadString, it will still need a call back on completion but the goal is to approach the appearance of synchronous code.  Here is the implementation:-

 

DownloadString
private static AsyncOperation DownloadString(Uri source, Action<String> returnResult)
{
    return (completed) =>
    {
        WebClient client = new WebClient();
        client.DownloadStringCompleted += (s, args) =>
        {
            try
            {
                returnResult(args.Result);
                completed(null);
            }
            catch (Exception err)
            {
                completed(err);
            }
        };
        client.DownloadStringAsync(source);
    };
}

 

The above function doesn’t actually do anything when called, it just returns a delegate matching the AsyncOperation signature.   When the returned operation is eventually invoked by the AsyncOperationService it will download a string from the Uri provided then, when downloaded string becomes available, pass it to the returnResult call back.   Now how does this help “approach the appearance of synchronous code” ?  Compare the following real code with the imaginary block of code above:-

 

Real Code
private IEnumerable<AsyncOperation> LoadExternalResources()
{
    XDocument manifest = null;

    yield return DownloadString(new Uri("External/ResourceManifest.xml", UriKind.Relative),
        manifestXml => manifest = XDocument.Parse(manifestXml) );

    foreach (XElement resourceElem in manifest.Descendants("resource"))
    {
        Uri resourceUri = new Uri(resourceElem.Attribute("source").Value, UriKind.Relative);
        yield return DownloadString(resourceUri, resourceXaml =>
        {
            var resource = XamlReader.Load(resourceXaml) as ResourceDictionary;
            Resources.MergedDictionaries.Add(resource);
        });
    }
}

   

 

 

 

A quick scan of this real code shows that it doesn’t differ much from the original imaginary synchronous code.  The fundamental flow of downloading a manifest then iterating over its content downloading the various dictionaries is identical to the original.  On closer inspection we see that the calls to an imaginary DownloadString have been replaced with calls to the actual DownloadString method declared above.  The returned AsynchOperation delegates are yielded and the result string is handled by a lambda passed to the returnResult callback.

 

yield return

The “enabler” in all of this is the C# yield return construct.  If you are not familiar with it may I suggest you first read the documentation here.  When a yield return is found in a method then its return type is expected to be an IEnumerable<T> where T is the type of the expression in the return.

Its useful to know that none of the code in such a method will execute until the first call to MoveNext on an enumerator created from it is made.  Code will then run in the method normally until a yield is reached at which time that call to MoveNext completes, the execution of the method effectively pauses, its state is maintained (I won’t go into how that is well covered elsewhere).  Only when another call to MoveNext is made does code in the method continue from the point of the last yield.  This call can happen much later, possibly from another thread.

In this specific case I am “pausing” the method’s execution each time an asynchronous operation is needed and yield an instance of AsyncOperation that implements that operation.  This just leaves the AsyncOperationService with the task of running the method by iterating over this yielded set of AsyncOperations, the service calls MoveNext to move the code forward.  It only calls MoveNext when the current AsyncOperation has been executed and completed.

In part 1 I indicated that it would be important to handle errors generated when calling MoveNext.  When iterating a set of items provided via yield return the MoveNext represents much more than a trivial “increment to the next item”, instead some significant code can be run.

Also in part 1 I emphasised the need for the AsyncOperationService to properly dispose of the IEnumerator<AsyncOperation> that it is iterating over.  When yield return is used within a using block or a try..finally block then code execution can escape the block.  If an exception were to occur it could leave these blocks of code in limbo without the finally code having executed.  Ensuring proper disposal causes this finally code to be executed thereby releasing anything the ought be disposed in a timely fashion.

 

What’s next?

If I ever get round to writing a Part 3 I’ll look at other common scenarios where a simple synchronous chunk of code can be “rotated” to use yield return and AsyncOperation.  For example sending and retrieving a stream via HttpWebRequest/HttpWebResponse can be somewhat ugly.  Also a sequence WCF calls may well benefit from this treatment too.  If you have any suggestions for scenarios, please post them in a comment.

Posted on Friday, October 15, 2010 9:32 PM Silverlight , AsyncOperationService | Back to top


Comments on this post: Simple Asynchronous Operation Runner – Part 2

No comments posted yet.
Your comment:
 (will show your gravatar)
 


Copyright © codingbloke | Powered by: GeeksWithBlogs.net | Join free