Saturday 28 January 2012

Asynchronous Method Wrapper

So I have finally created an asynchronous wrapper for my web service assignment, allowing any method to called asynchronously. I'll give a quick demo of how it work:

1.  The Method Call
A method from within an asynchronous wrapper class.
So, we start off with the wrapped method, in this case the GetUserAsync method is going to allow us to retrieve a specific user asynchronously. The method makes a call to DoAsync, inherited from the AsyncCalls class (which will be discussed later), passing the GetUser method (Converted into the right format, see number 2), the parameters it requires in an object array, and the name of the event.

 2. Converting the method format
The DoAsync method from the AsyncCalls class
The reason the GetUser need to be converted when being passed to DoAsync, is because it does not match the GenericAsyncDelegate signature.

The GenericAsyncDelegate signature for a method which takes an object[]  a string and returns an AsyncData object
So to convert GetUser (A method that takes an int and returns a WebUser object) into the right format, I call the ConvertFuncSingleArg method.

ConverFuncSingleArg method returning a method converted into a GenericAsyncDelegate.
As you can see the method returns an anonymous delegate in the form of a GenericAsyncDelegate, using ConvertResult to change the result of passed method into an object[], allowing it to be wrapped in a AsyncData object. Because the methods return type is unknown until runtime, problems are caused if a collection is passed. A simple example of this would be if the return type was List<Object>,  T would be assigned this type when the method is called, and all the checks will fail, as T is not an array and is not of type List<List<Object>>, so the method will return object[] {List<Object>}.

A method to convert the object passed into an object[]
To solve the above problem, the generic type passed must be the return type in a non-collective form. This can be done using reflection, so I created a method as a layer to do this.

The middle layer of converting the return type.

First of all, temp is set to the type of T, so if all tests fail, it is treated as the return type. Then I check if it is a type of array, if this is true then temp is set to the element type, otherwise treat it as a generic collection attempt to take it's generic type, if a generic type is found then set temp. In the above case Type.GetType will work as object is part of the referenced System namespace, but in cases where the type does not exist in a referenced namespace, the DLL needs to be loaded, and the type retrieved from it. Once the checks are complete the ConvertReturnType method needs to be called with temp as it's generic type, I use reflection to create the method, then invoke it with with MethodResult as a parameter.

3. The DoAsync Method
DoAsync method which sets up the process.
The method starts by defining the callback delegate, this is the method is used to process the result of the async call, in this case the method will be called GenericAsyncCompleteCallback. Secondly creates a AsyncOperation object with no state, which is used to track and report the progress of the operation. Finally Istart the method (notice BeginInvoke being used not Invoke, as Invoke is synchronous), we pass the two GenericAsyncDelegate parameters, a reference to the callback, and the AsyncOperation object.

4. The Callback
The callback method.
The callback method gets passed an object of IAsyncResult, which contains objects relating to the async call. I then extract the objects I want; the method doing the work and the state of the operation. I then create the GenericAsyncCompletedEventArgs object (an extension of the AsyncCompletedEventArgs class) containing the result of the async operation, which will be passed to the event handler. Finally we update the state of the AsyncOperation to completed, specifying the operation complete method (which will be called after this) and the event arguments.

5. Completed Call
The even called on completion.
The only job of the OnGenericAsyncCompleted method is to fire the event handler, once the operation is complete.
The delegate for the event handler, and the event to be handled.
6. The End
Now everything is complete I can show you the code in a working context.
A test situation
Thank you for reading, my next post is most likely to be based on my Lisp assignment, hopefully you will enjoy it.

Liam 



No comments:

Post a Comment