Skip Navigation LinksHome > View Post

Filter this (Day 3)

One of my favorite hidden nuggets in Mobile Services is Service Filters. Service Filters allow you to place an interceptor between your client’s CRUD calls and the server. There are many useful applications for this, but one of my favorites is the ability to easily create a ‘busy’ or ‘activity’ indicator based on in-flight requests to the your Mobile Service. Here’s how in C#:

public class MyServiceFilter : IServiceFilter
{
    private int _callCount = 0;
    private Action<bool> _busyIndicator;

public MyServiceFilter(Action<bool> busyIndicator) { _busyIndicator = busyIndicator; }

public Windows.Foundation.IAsyncOperation<
IServiceFilterResponse> Handle( IServiceFilterRequest request, IServiceFilterContinuation continuation) { return HandleAsync(request, continuation).
AsAsyncOperation(); }

private async Task<IServiceFilterResponse> HandleAsync( IServiceFilterRequest request, IServiceFilterContinuation continuation) { // update the count by one in a single atomic operation. // If we get a 1 back, we know we just went 'busy' var outgoingCount = Interlocked.Increment(ref _callCount); if (outgoingCount == 1) { _busyIndicator(true); }

IServiceFilterResponse response = await continuation.Handle( request).AsTask();

// decrement the count by one in a single atomic operation. // If we get a 0 back, we know we just went 'idle' var incomingCount = Interlocked.Decrement(ref _callCount); if (incomingCount == 0) { _busyIndicator(false); }

return response; } }

The first step is to implement the IServiceFilter interface from the Microsoft.WindowsAzure.MobileServices namespace. There is just one method to implement called Handle. In the code above,  I simply delegate to HandleAsync to keep the code somewhat cleaner and allowing me to use .Net’s awesome Task framework. HandleAsync is where all the magic happens.

Inside HandleAsync, we know we have an outgoing call about to be started to increment the filter’s in-flight call count by one. If the call count is 1, we know we just went from no inflight calls to some, so we call the ‘busy’ delegate.

Next we actually invoke the server by calling Handle on the continuation parameter. Thanks to the awesome await keyword, we can keep our incoming response code right inline in the same method, and this is where we decrement the filter’s call count. If we have a new total of 0, we know we just went ‘idle’ and invoke the busy delegate with a value of false.

It really couldn’t be easier!

And now, to consume this filter we have to wrap our MobileServiceClient instance as follows:

var filter = new MyServiceFilter(busy =>
{
      // update the status of the busy indicator based on the status change
      progressControl.Visible = busy ? Visibility.Visible : Visibility.Collapsed;
}));

// use the newClient instance for all operations that should use busy tracking
var newClient = originalClient.WithFilter(filter);

You can also use filters in our WinJS client and the Objective C client for iOS. If you checkout the iOS quickstart you’ll notice that you get a sample implementation for free.

iOS (Objective C)

In iOS, using a service filter is as easy as implementing the MSFilter protocol, here’s an example:

- (void) handleRequest:(NSURLRequest *)request
                onNext:(MSFilterNextBlock)onNext
            onResponse:(MSFilterResponseBlock)onResponse
{
    // A wrapped response block that decrements the busy counter
    MSFilterResponseBlock wrappedResponse = ^(NSHTTPURLResponse *response, 
NSData *data,
NSError *error) { [self busy:NO]; onResponse(response, data, error); }; // Increment the busy counter before sending the request [self busy:YES]; onNext(request, wrappedResponse); }

And then in the same class, we have a busy method:

- (void) busy:(BOOL) busy
{
    // assumes always executes on UI thread
    if (busy) {
        if (self.busyCount == 0 && self.busyUpdate != nil) {
            self.busyUpdate(YES);
        }
        self.busyCount ++;
    }
    else
    {
        if (self.busyCount == 1 && self.busyUpdate != nil) {
            self.busyUpdate(FALSE);
        }
        self.busyCount--;
    }
}

To see this in action, just try the iOS quickstart

image

This was Day 3 in the series The twelve days of ZUMO. We’ll have more tomorrow.

 
Josh Post By Josh Twist
1:53 AM
24 Dec 2012

» Next Post: Getting started with the CLI and backing up your scripts (Day 4)
« Previous Post: It&rsquo;s time for CRON (Day 2)

Comments are closed for this post.

© 2005 - 2014 Josh Twist - All Rights Reserved.