>
Demo Banner

In building the Silverlight client for Dataphor, we built a simple helper class that makes asynchrony much easier to deal with. This class has proven useful for composing UI logic for several other projects as well, so we thought it would be useful to share. The jury is still out whether or not the coming "await" syntax for C# could fully replace this given that it deals with functions, not imperative logic, but we'll see...

The gist is that the WorkerQueue allows actions to be scheduled on a single worker thread, with the ability to schedule-and-wait back onto the UI thread. Each instance of the class represents a single worker thread, which generally will suffice for each form or even the entire client.
Arguments for this pattern include:
• Long-running UI logic, such as service calls, can be composed in an imperative, synchronous like manner without the scattering of logic across a chain of asynchronous callbacks.
• State management becomes much simpler by use of the standard imperative constructs such as local variables.
• By limiting asynchrony to a single thread, the problem of compounding race conditions is alleviated. For instance, most asynchronous UIs are subject to problems such as the user quickly pressing the delete and update actions for the same row. By queuing those actions onto a single thread, the user is exposed to the expected behavior or each action being executed in the order it was performed.
There are of course some caveats, including:
• To make full use of this pattern, service calls should be exposed as synchronous, which Silverlight not only doesn’t generate, but makes quite difficult to implement. A couple remedies follow.
• Because the pattern seems so synchronous, one must remember to be carefully cognizant of cross thread state access.
The two main calls on WorkerQueue are Queue and DispatchAndWait. Queue queues up an action for execution on the worker; DispatchAndWait executes an action on the main (UI) thread and waits for it’s completion before returning. The resulting usage pattern ends up looking something like this:
public void BeginSaveTitle()
{
Worker.Queue
(
() =>
{
string LTitle = null;

try
{
Worker.DispatchAndWait
(
() =>
{
// Capture title while on the main thread
LTitle = Title;

SetStatus(SessionStatus.SaveTitle);
}
}
);

var LClient = new DocumentServiceClient();
LClient.SetTitle(DocumentID, LTitle);
}
catch (Exception LException)
{
HandleAsyncException("save title", LException);
}
}
);
}


This pattern allows you to move back and forth between the worker thread and the UI thread and be sure that a) you are the exclusive worker; and b) the actions will happen in sequence. The WorkerQueue also has an event that fires when all work has been serviced and it is returning to idle, which can be called to automatically clear a status flag or whatever. I typically tie this functionality to a “busy” indicator in the UI.
The last thing to discuss is accomplishing the synchronous pattern in WCF. Basically you have to write your service wrapper manually. Here is an example of the approach using a ClientBase:
public class DocumentServiceClient : ClientBase, IDocumentService
{
public void SetTitle(Guid ADocumentID, string ATitle)
{
var LResult = base.Channel.BeginSetTitle(ADocumentID, ATitle, null, null);
LResult.AsyncWaitHandle.WaitOne();
base.Channel.EndSetTitle(LResult);
}

Note that this wrapper nor the synchronous interface will not be generated by a service reference import; you’ll have to write or generate the client. The synchronous interface is easily obtainable through a service reference import into a non-Silverlight project or from the service itself if it is .NET.
The WorkerQueue code may be downloaded here.

Add a Comment

DCG Out and About

Demo Image

Database Consulting Group in the Community

We are working with teams from universities to give the work experience they will need to get a job after graduation
If you have projects, that would help the community that relate to our business, let us know.