Going Asynchronous with Sterling for Windows Phone 7

November 13, 2010 | Async

In this post I discuss about the various programming models that can be used with Sterling Isolated Storage Database for Windows Phone 7. Further, I discuss how one can benefit from the Power Threading Library when using Sterling.

Extension methods for the ISterlingDatabaseInstance interface

I have already discussed about the basics of Sterling Isolated Storage Database (Sterling) when building application for Windows Phone 7 (WP7). At times you might want to do some operation on the background while your code executes something else.

Sterling supports the Event-based Asynchronous Pattern (EAP) which means you can write the following code against the ISterlingDatabaseInstance interface:

private void ExecuteWithEventBased()
{
    IList<Cargo> cargos = new List<Cargo>();
    for (int n = 0; n < iterations; n++)
    {
        Cargo cargo = CargoFactory.CreateNew("Glyfada" + n, "Perachora" + n);
        cargos.Add(cargo);
    }

    var bw = App.Database.SaveAsync<Cargo>(cargos);
    bw.RunWorkerCompleted += (sender, e) => {
        SetStatus("Event-based completed.", StatusState.Ready); };

    bw.RunWorkerAsync();
}

I can imagine, the reason the EAP is implemented is because you can have progress notification while the I/O executes in the background and also for handling the SynchronizationContext and/or the Dispatcher internally.

In my applications, I prefer to use the IAsyncResult, the CLR’s Asynchronous Programming Model (APM). For that reason, I wrote some extension methods for the ISterlingDatabaseInstance interface that allows you to use the APM when working with Sterling.

Power Threading library comes with an implementation of the IAsyncResult interface, so one can take a method that executes synchronously and implement the APM. In the code above you can see the APM for the object Save<T>(T instance) where T : class, new(); method in ISterlingDatabaseInstance interface.

/// <summary>
/// Asynchronous version of ISterlingDatabaseInstance Save method (Begin part).
/// </summary>
public static IAsyncResult BeginSave<T>(
    this ISterlingDatabaseInstance sterling,
    T instance,
    AsyncCallback callback,
    object state) where T : class, new()
{
    // Create IAsyncResult object identifying the asynchronous operation.
    AsyncResult ar = new AsyncResult(callback, state);

    // Use a thread pool thread to perform the operation.
    ThreadPool.QueueUserWorkItem((obj) =>
    {
        var asyncResult = (AsyncResult)obj;
        try
        {
            // Perform the operation.
            sterling.Save<T>(instance);
            asyncResult.SetAsCompleted(null, false);
        }
        catch (Exception e)
        {
            // If operation fails, set the exception.
            asyncResult.SetAsCompleted(e, false);
        }
    }, ar);

    return ar; // Return the IAsyncResult to the caller.
}

///<summary>
/// Asynchronous version of ISterlingDatabaseInstance Save method (End part).
/// </summary>
public static void EndSave(
    this ISterlingDatabaseInstance instance,
    IAsyncResult asyncResult)
{
    AsyncResult ar = (AsyncResult)asyncResult;
    ar.EndInvoke();
}

AsyncResult class resides in the PowerThreading library. It is written by Jeffrey Richter and can be obtained from the Wintellect website. 

Sterling Isolated Storage Database can be obtained from the CodePlex website.

Armed with the above extension method you can write the following code which combines the APM implementation with the AsyncEnumerator class.

// Inside your method create an instance of an AsyncEnumerator class,
// specifying the iterator method to be driven by the AsyncEnumerator.
AsyncEnumerator ae = new AsyncEnumerator();
ae.BeginExecute(ExecuteWithAsyncEnumerator(ae), ae.EndExecute, null);

private IEnumerator<int> ExecuteWithAsyncEnumerator(AsyncEnumerator ae)
{
    for (int n = 0; n < iterations; n++)
    {
        Cargo cargo = CargoFactory.CreateNew("Glyfada" + n, "Perachora" + n);
        App.Database.BeginSave<Cargo>(cargo, ae.End(), null);
    }

    // AsyncEnumerator captures the calling thread's SynchronizationContext.
    // Set the SyncContext to null so that the callback continues
    // on a ThreadPool thread.
    ae.SyncContext = null;

    yield return iterations;

    for (Int32 n = 0; n < iterations; n++)
    {
        App.Database.EndSave(ae.DequeueAsyncResult());
    }

    // AsyncEnumerator captures the synchronization context.
    SetStatus("AsyncEnumerator completed.", StatusState.Ready);
}

The sample Windows Phone 7 application can be found here.