Windows Phone 7 and WCF Don’t Play Nicely

Windows Phone 7 and WCF Don’t Play Nicely

There area a number of ways you can access data from within your Windows Phone 7 application. These include using base level classes such as HttpWebRequest and the WebClient but you can also use WCF from within your application. The advantage of using WCF is of that Visual Studio 2010 can generate the necessary strongly typed proxy classes for you. All you need to do is click “Add Service Reference”, enter the url for the service you want to import and off you go. You can now write code that connects to a WCF service… happy days…. fail

Unfortunately it attempting to make life easier for noobie developers the Silverlight/Windows Phone 7 teams have managed to create a rod for almost any serious developer who wants to work with WCF Services. I’ll cover this in two parts as follows:

Async Methods Suck!

If you’ve worked with Silverlight on the desktop or WP7 then you’ll probably have noticed that nearly all methods that perform a network operation are asynchronous. This is true of the base HttpWebRequest class, the WebClient and WCF proxy classes. Conceptually this is quite a good idea as it forces developers to think asynchronously and write code that doesn’t block the UI thread. This in theory should lead to responsive applications.

What this doesn’t take into consideration is that developers who have done a programming 101 course understand the use of multiple threads. If you spin up another thread to do background tasks such as synchronisation then all of a sudden you’re going to find yourself fighting the async programming model that’s been thrust on you.

What we want to be able to do is something like:

Service1Client client = new Service1Client();
public void RunInBackground(){
    client.Step1();
    client.Step2();
}
 

What we end up with instead is:

Service1Client client = new Service1Client();
public void RunInBackground(Action callback) {     
    client.Step1Completed += client_Step1Completed;     
    client.Step1Async(callback);
}
 
void client_Step1Completed(object sender, Step1CompletedEventArgs e) {     
    client.Step1Completed -= client_Step1Completed;     
    client.Step2Completed += client_Step2Completed;     
    client.Step2Async(e.UserState);
}
 
void client_Step2Completed(object sender, Step2CompletedEventArgs e) {     
    client.Step2Completed -= client_Step2Completed;     
    var callback = e.UserState as Action;     
    callback.Invoke();
}
 

Note that the RunInBackground takes an Action as a callback. This is passed along with the various WCF method calls so that it can be invoked when all of the services have completed. Notice how untidy this code is and just how difficult it is to read and maintain.

There are ways to beat Silverlight into shape to make it easier to do a sequence of service calls on a background thread. For example the following ServiceHelper class means that I can call the sequence of Step1 and Step2 in a synchronous fashion. Note that this is done on a background thread.

void MainPage_Loaded(object sender, RoutedEventArgs e) {         
    ThreadPool.QueueUserWorkItem(async => RunInBackground());
}
 
Service1Client client = new Service1Client();
public void RunInBackground(){
    ((Action)client.Step1Async).ServiceCall<Step1CompletedEventArgs>(             
            handler => client.Step1Completed += handler,             
            handler => client.Step1Completed -= handler);
    ((Action)client.Step2Async).ServiceCall<Step1CompletedEventArgs>( 
            handler => client.Step2Completed += handler, 
            handler => client.Step2Completed -= handler); 
}

 
public static class ServiceHelper {     
    private static object downloadLock = new object();     
    private static AutoResetEvent downloadWait = new AutoResetEvent(false);     
    public static T ServiceCall<T>(this Action serviceCall, 
                                     Action<EventHandler<T>> addHandler, 
                                     Action<EventHandler<T>> removeHandler) where T : AsyncCompletedEventArgs {         
        lock (downloadLock){             
             T data = default(T);             
             EventHandler<T> handler = (s, e) =>
             {
                 data = e;
                 downloadWait.Set();
             };
          addHandler(handler);             
             serviceCall();             
             downloadWait.WaitOne();        
             removeHandler(handler);             
             if (data.Error != null) {                 
                 throw data.Error;             
             }             
             return data;         
        }     
    }
}

 

WCF Implementation Sucks!

A nasty surprise awaits those attempting to use WCF on Windows Phone 7. What it little understood is that the proxy classes that Visual Studio generates (which inherit from ClientBase) has some awful code behind it that will flick execution back onto the Main/UI thread. As you saw previously each WCF service call is made up of an asynchronous method call, with a completed event that is raised when the service call returns. This event is raised on the Main/UI thread. This means that if you’re doing any sort of processing (eg writing the response to disk before displaying it) you will accidentally block the UI thread!!!

I’m sorry to say this is one of the worst architectural decisions I’ve seen in a long time and is a hidden cause for so many applications performing badly. There are a couple of solutions:

1) Use HttpWebRequest and use a REST API on the server

2) Jump off the UI thread in each event handler, do the processing and then jump back to UI thread to update the UI.

3) The ServiceHelper shown earlier automatically passes back off to the background thread.

Leave a Reply

Your email address will not be published. Required fields are marked *