Geeks With Blogs

@codingbloke
  • codingbloke Blogged: Using the AsyncOperationService with HttpWebRequest. Builds on the previous .NET Async Pattern stuff. http://t.co/B5VLg8a about 1171 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 1213 days ago
  • codingbloke @Pete_Brown I like "custom" mode, gives me the warm fuzzy feel that I'm in control about 1389 days ago

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

I’ve been meaning to create a blog about asynchronous operations in Silverlight for sometime.  Specifically how to create code that looks and behaves much like synchronous code that actually depends on asynchronous operations.   I’ve seen quite a number of questions on Stackoverflow where developers have discovered that in many cases Silverlight only supports performing tasks asynchronously.

There are number of solutions that others, more able than I, have blogged about along with excellent explanations of the problem.  I’ll assume the reader is already familiar with the problem itself.

It seemed to me that the existing solutions I’d seen added more infrastructure than is needed to solve the fundamental problem.  Also some of the example implementations did not deal with exceptions as robustly as I would have liked.  My goal then is to create only enough code to actually solve the problem and handle exceptions well.

I felt that it ought to be possible to define each asynchronous operation as a simple delegate.  Here is the delegate definition I came up with:-

    
    public delegate void Operation(Action<Exception> completed);

 

An asynchronous operation would simply call the completed Action once it has (believe it or not) completed, it would pass any exception as a parameter or null if the operation succeeded.   To execute a sequence of these should be quite easy, the following is a naive attempt at a sequential runner for these operations (N.B. Don’t use this code).

 

        public static void NaiveRunner(IEnumerable<Operation> asyncOps, Action<Exception> completed)
        {
            IEnumerator<Operation> enumerator = asyncOps.GetEnumerator();
            Action executeNextOp = null;
            executeNextOp = () =>
            {
                if (enumerator.MoveNext())
                {
                    enumerator.Current((err) =>
                    {
                        if (err != null)
                            completed(err);
                        else
                            executeNextOp();
                    });
                }
                else
                {
                    completed(null);
                }
            };
            executeNextOp();
        }

 

This code becomes quite straight forward if you can visualise the two nested lambdas. The outer lambda assigned to executeNextOp gets the next operation and executes it.  The inner lambda is passed as the completed parameter when the operation is called.  Hence when the operation completes this inner lambda is executed which will in turn call executeNextOp if there was no error.  This continues until all items have been iterated.

There are a lot of problems with this code, I only included it so that the bare bones of the solution can be seen.  Here are the problems:-

  • What if the “synchronous bit” of the operation throws an error?  Say for example the operation is using WebClient.OpenReadAsync with a duff Uri.  Currently the above code doesn’t handle that scenario.
  • What if the MoveNext throws an error?  In part 2 I’ll come back to why that is a distinct possibility so it needs to be addressed.
  • What if the operation attempts to call the completed callback more than once?  A mechanism to prevent a massive tear in the time-space continuum would need to be in place here.
  • My personal favourite, the enumerator requires disposal.  Its not uncommon for the object returned by GetEnumerator to require correct disposal, the technique I’ll show in part 2 will certainly create such an enumerator.  The foreach statement which is the normal consumer of IEnumerables handles this even in error conditions.  The code above would need modifying to handle disposal correctly too.
    Taking all that on board here is my complete AsyncOp class which I believe is all the infrastructure you need to sequentially execute asynchronous operations.

 

AsyncOperationService
    public delegate void AsyncOperation(Action<Exception> completed);

    public static class AsyncOperationService
    {
        public static void Run(this IEnumerable<AsyncOperation> asyncOps, Action<Exception> completed)
        {
            IEnumerator<AsyncOperation> enumerator = asyncOps.GetEnumerator();

            Action<Exception> disposeAndComplete = (exception) =>
            {
                enumerator.Dispose();
                completed(exception);
            };

            Action executeNextOp = null;
            executeNextOp = () =>
            {
                bool asyncCallbackExecuted = false;
                bool sequenceIncomplete = true;

                try
                {
                    sequenceIncomplete = enumerator.MoveNext();
                    if (sequenceIncomplete)
                    {
                        enumerator.Current((asyncError) =>
                        {
                            if (!asyncCallbackExecuted)
                            {
                                asyncCallbackExecuted = true;

                                if (asyncError == null)
                                    executeNextOp();
                                else
                                    disposeAndComplete(asyncError);
                            }
                        });
                    }
                }
                catch (Exception syncError)
                {
                    disposeAndComplete(syncError);
                }

                if (!sequenceIncomplete)
                    disposeAndComplete(null);

            };
            executeNextOp();
        }

    }

This code takes the original naive attempt and expands upon it to solve all the issues I bulleted above.  As far as I can tell this meets my original goal of having a complete solution with just enough code and no more.

In Part 2 I will explore its usage and the inevitable creation of utility functions what might otherwise have already come with a fully-fledge “frameworked” solution.

Posted on Sunday, September 12, 2010 9:55 PM Silverlight , AsyncOperationService | Back to top


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

# re: Simple Asynchronous Operation Runner – Part 1
Requesting Gravatar...
Hi Anthony,

For a newbie like me in silverlight and .net 4.0, the above code was little bit complex but i learned a lot from the above snippet..important concept in async operations in silverlight.

Just wanted to say thank you.

Cheers

Shirish
Left by Shirish Nigam on Jul 29, 2011 9:42 AM

Your comment:
 (will show your gravatar)


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