Windows Phone 7 and WCF Don’t Play Nicely

by Nick 20. April 2011 16:39

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.

Tags:

Comments (6) -

4/20/2011 6:33:22 PM #

Jose Fajardo

I'm making no excuse for Silverlights WCF's performance on WP7, it should definetely be optimized. BUT this may explain there strategy for threading..

http://tomasz.janczuk.org/2009/08/improving-performance-of-concurrent-wcf.html

If WP7 is the same as Desktop SL then they definetely should optimize this scenario for WP7, theres never an excuse to hold up the UI thread if one can help it!

Jose Fajardo Australia |

4/20/2011 6:45:33 PM #

Nick

I could be wrong but when you trigger a WCF call from a background thread on wp7, when it returns you're magically on the UI thread again. Always happy to be proven wrong though

Nick Australia |

4/21/2011 2:10:09 AM #

Levente

This gave me some headaches too until I figured out the cause. Chose option 2)  and it indeed resulted some hard-to-maintain code. I'll try your ServiceHelper class, thanks for that.

Levente Hungary |

4/21/2011 6:33:15 AM #

Simon (Darkside) Jackson

This is where Reactive Programming (#RX) comes to the rescue.
For asynch operations it adds a layer of abstraction and control plus "Error handling".

Anyone considering doing web stuff on the phone I highly recommend learning at least the basics of #RX in relation to WCF calls and HTTPWebRequest.
You will also find it's useful for so many other backend or asynch operations.

See Jessie Liberties Blog (jesseliberty.com/reactive-extensions-rx/) for more info, or the recent WP7 web webcast I did (on XNA-UK)

Simon (Darkside) Jackson United Kingdom |

4/23/2011 1:38:16 PM #

Tom

Using the thread pool for IO operation (or for IO operation handling, like you) is not a good approach, because it was designed for computing purpose. Creating a new thread would be better, but it is resource heavy. That is why APM exists and is the recommended way to use WCF now. I admit it is uncomfortable to use, but with the new async keyword things will be changed:

http://blogs.msdn.com/b/endpoint/archive/2010/11/13/simplified-asynchronous-programming-model-in-wcf-with-async-await.aspx


Tom United Kingdom |

4/23/2011 8:51:36 PM #

Nick

Tom, I think you're missing the point about the post. I'm not going to get into a debate as to whether queuing the method to be run in the background via the ThreadPool, or spinning up a new thread is better. The upshot is that you're doing a sequence of activities in the background that do not directly involve the user interface (synchronizing data for example). Having the ability to do wcf calls in a synchronous manner as I've illustrated just simplifies the logic and makes the code infinitely easier to follow.

I also don't believe the async keyword will actually yield as many benefits as MS are suggesting. Specifically in the case of WCF services in Silverlight/WP7 where the methods are already async (with an event callback). You're still going to have to wrap these method calls to force them back into some sort of synchronous model.... only to then apply the async keyword to that method... seems a waste of time to me.

Nick Australia |

Pingbacks and trackbacks (2)+

Powered by BlogEngine.NET 2.0.0.36

Automotive Theme by Car Leasing Experts

 

Page List