Mike Taulty's Blog
Bits and Bytes from Microsoft UK
Silverlight and Synchronous Network Calls

Blogs

Mike Taulty's Blog

Elsewhere

Archives

Someone tweeted on Twitter that they wanted to stop the UI thread in Silverlight while they performed a couple of asynchronous network activities because one activity depended on the output of another.

To be honest, I don’t really like the idea and I’ve drawn this slide in the past;

image

where I’ve advised people not to try and subvert the asynchronous networking aspects of Silverlight so I suppose it’s no surprise that I’m not a big fan of trying to block the UI thread while networking activity completes.

Let’s say I’ve got this simple web service to invoke;

[ServiceContract]
public interface IService
{
  [OperationContract]
  string InitialCall();

  [OperationContract]
  string SubsequentCall(string input);
}
and all it does is return hard-coded strings;
public class Service : IService
{
  public string InitialCall()
  {
    return ("Hello");
  }

  public string SubsequentCall(string input)
  {
    return (input + " World");
  }
}
but to call it, I need to make 2 asynchronous trips across the network to invoke the InitialCall operation and then the SubsequentCall operation with the idea being that the second operation gets passed the results from the first one.

Now, in the Silverlight world the WCF proxy generation tools in Visual Studio will represent these asynchronous operations using the Event Based Asynchronous Pattern giving me an initial method to call XXXAsync and an EventArgs derived from AsyncCompletedEventArgs.

If I create a quick view;

<UserControl
  x:Class="SilverlightApplication5.MainPage"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  mc:Ignorable="d"
  d:DesignHeight="300"
  d:DesignWidth="400"
  xmlns:local="clr-namespace:SilverlightApplication5">
  <UserControl.DataContext>
    <local:ViewModel />
  </UserControl.DataContext>
  <Grid
    x:Name="LayoutRoot"
    Background="White">
    <Grid.RowDefinitions>
      <RowDefinition />
      <RowDefinition
        Height="Auto" />
    </Grid.RowDefinitions>
    <Viewbox>
      <TextBlock
        Text="{Binding DisplayText}" />
    </Viewbox>
    <Button
      Grid.Row="1"
      Content="Click"
      Command="{Binding InvokeServiceCommand}" />
  </Grid>
</UserControl>
and a quick view model behind it;
  public class ViewModel : INotifyPropertyChanged
  {
    public ViewModel()
    {
      this.invokeServiceCommand = new SimpleCommand(
        OnInvokeService);
    }
    void OnInvokeService()
    {
      // Invoke the 2 service methods asynchronously and then
      // change the DisplayText property to reflect that.
    }
    public ICommand InvokeServiceCommand
    {
      get
      {
        return (this.invokeServiceCommand);
      }
    }
    SimpleCommand invokeServiceCommand;

    public string DisplayText
    {
      get
      {
        return (_DisplayText);
      }
      set
      {
        _DisplayText = value;
        RaisePropertyChanged("DisplayText");
      }
    }
    string _DisplayText;

    void RaisePropertyChanged(string property)
    {
      if (this.PropertyChanged != null)
      {
        this.PropertyChanged(this,
          new PropertyChangedEventArgs(property));
      }
    }
    public event PropertyChangedEventHandler PropertyChanged;
  }

( with SimpleCommand being just a simple implementation of ICommand ).

Then the question becomes one of how I can implement the OnInvokeService method with the minimum of pain. Here’s one approach;

    void OnInvokeService()
    {
      ServiceClient proxy = new ServiceClient();
      proxy.InitialCallCompleted += OnInitialCallCompleted;
      proxy.InitialCallAsync();
    }
    void OnInitialCallCompleted(object sender, InitialCallCompletedEventArgs e)
    {
      ServiceClient proxy = (ServiceClient)sender;
      proxy.InitialCallCompleted -= OnInitialCallCompleted;

      // TODO: Need a way to deal with the errors and cancellation.
      if (!e.Cancelled && (e.Error == null))
      {
        proxy.SubsequentCallCompleted += OnSubsequentCallCompleted;
        proxy.SubsequentCallAsync(e.Result);
      }
    }
    void OnSubsequentCallCompleted(object sender, SubsequentCallCompletedEventArgs e)
    {      
      ServiceClient proxy = (ServiceClient)sender;
      proxy.SubsequentCallCompleted -= OnSubsequentCallCompleted;

      // TODO: Ditto
      if (!e.Cancelled && (e.Error == null))
      {
        this.DisplayText = e.Result;
      }
    }
This is fairly repetitive but it’s fairly simple – we’re chaining together calls until they end. I find it’s actually easier to write explicit methods for the handlers because if you don’t and write anonymous methods then you have to keep a reference around to the delegate so that you can unsubscribe from the events.

Naturally, we could easily use something like a BusyIndicator to make some or all of our UI busy while these 2 asynchronous operations are in progress, taking care to make sure that we cancel the busy state in the case of all different kinds of completion (errors, cancellation, success). There’s no need for the user to “interfere” with the application while our async work is in flight, unless we explicitly want them to.

Alternatively, we could try and pretend that this call is synchronous. Perhaps something along the lines of;

    void OnInvokeService()
    {
      ServiceClient proxy = new ServiceClient();
      string result = string.Empty;

      AutoResetEvent evt = new AutoResetEvent(false);      

      proxy.InitialCallCompleted += (s, e) =>
        {
          proxy.SubsequentCallAsync(e.Result);
        };

      proxy.SubsequentCallCompleted += (s, e) =>
      {
        result += e.Result;
        evt.Set();
      };  

      proxy.InitialCallAsync();    

      evt.WaitOne();

      this.DisplayText = result;
    }
This initially looks like less hassle but this code isn’t going to work for us although it tries to code block the UI thread on line 21 until the two asynchronous operations complete.

The WCF proxy here is set up to be friendly towards us in that it attempts to deliver events like InitialCallCompleted back to the UI thread so that we don’t have to deal with being “on the wrong thread” for the completion of the event.

That’s a nice thing for the proxy to do for us.

However, it breaks our code here causing it to deadlock. There’s no way for the WCF proxy code to get back to our UI thread and ask it to dispatch messages because our UI thread is blocked in a call to WaitHandle.WaitOne and so it can’t dispatch messages which means that we deadlock and never invoke the lambda on line 10.

This deadlock is kind of interesting because while I’m deadlocked on that WaitOne I can exercise my browser and see how well it (IE 9) deals with this UI thread being blocked.

image

The effect of blocking the UI thread has been not only to hang the tab with the Silverlight application, it’s hung the whole browser. I cannot type into the address bar. I cannot browse to another site. The whole thing’s gone horribly wrong.

That’s not a criticism of IE - I shouldn’t have written code that blocked the UI thread. I was guided not to do it Smile

Now, it’s worth saying that if we weren’t using a WCF proxy but were, instead, using something that exposed the traditional Asynchronous Programming Model like the HttpWebRequest class for instance that does not try and marshal its asynchronous results back to the UI thread then we would not have hit our deadlock but we would still have blocked the UI thread for some period of time that isn’t really within our control and the user’s experience is poor.

I’d avoid it. I’d use the former asynchronous model and never try and pretend that we’re working synchronously when we’re not.

That said, there are lots of different ways that original code could have been written including some newer options…

Trying the Async CTP

If I was using the Async CTP then I might be able to make use of the new await construct. I had a stab at that;

    async void OnInvokeService()
    {
      ServiceClient proxy = new ServiceClient();

      var initialHandler = new TcsHandler<InitialCallCompletedEventArgs, string>(
          args => args.Result);

      proxy.InitialCallCompleted += initialHandler.Handler;
      proxy.InitialCallAsync();
      await initialHandler.TaskCompletionSource.Task;
      proxy.InitialCallCompleted -= initialHandler.Handler;

      var subsequentHandler = new TcsHandler<SubsequentCallCompletedEventArgs, string>(
        args => args.Result);

      proxy.SubsequentCallCompleted += subsequentHandler.Handler;
      proxy.SubsequentCallAsync(initialHandler.Result);
      await subsequentHandler.TaskCompletionSource.Task;
      proxy.SubsequentCallCompleted -= subsequentHandler.Handler;

      this.DisplayText = subsequentHandler.Result;
    }
This now looks fairly neat and tidy. It looks like synchronous code when it isn’t. The only problem I had in putting that together was how to go from the WCF proxy code which uses event handlers with arguments derived from AsyncCompletedEventArgs to something that matches the Async CTP’s awaitable pattern.

I tried to do that by relying on TaskCompletionSource and Task and I wrote a little class to help me with that – TcsHandler below. Perhaps there’s a better way?

  public class TcsHandler<E,T> where E : AsyncCompletedEventArgs
  {
    public TcsHandler(Func<E,T> selector)
    {
      this.TaskCompletionSource = new TaskCompletionSource<T>();
      this.selector = selector;
    }
    public T Result
    {
      get
      {
        return (this.TaskCompletionSource.Task.Result);
      }
    }
    public void Handler(object sender, E args)
    {
      if (args.Cancelled)
      {
        this.TaskCompletionSource.SetCanceled();
      }
      else if (args.Error != null)
      {
        this.TaskCompletionSource.SetException(args.Error);
      }
      else
      {
        this.TaskCompletionSource.SetResult(
          this.selector(args));
      }
    }
    public TaskCompletionSource<T> TaskCompletionSource
    {
      get;
      private set;
    }
    Func<E, T> selector;
  }
This little helper class would be easier to implement if AsyncCompletedEventArgs had a friend AsyncCompletedEventArgs<T> but it doesn’t and so I tried to solve the problem of;

“how does this class go from an instance of something derived from AsyncCompletedEventArgs to be able to call TaskCompletionSource<T>.SetResult

by introducing a simple projection function to the constructor that can be used to extract the data that’s needed.

Now…I’m pretty sure that when the Async CTP comes to fruition, the tools such as the proxy-generation tool for WCF services would be updated to use the Task Asynchronous Pattern rather than the Event based Asynchronous Pattern that they’re using here for Silverlight so things should get a lot easier.

Another option…

Trying Rx

If I wasn’t using the Async CTP but was perhaps using Rx then I could take a different approach to making these 2 asynchronous calls. Rx bridges nicely to the world of .NET events.

In this particular case though, I want to be able to bridge to the WCF proxy which is using the Event based Asynchronous Pattern and in each case I need to be able to;

  1. Invoke some initial operation to make the WCF call. For example – to call proxy.InitialCallAsync
  2. Harvest the results from some AsyncCompletedEventArgs derived class.

I’m not 100% whether there’s an easier way of doing this or whether I got it nearly correct but I made an attempt at something that tried to do that to produce an IObservable<T>;

    static IObservable<T> FromAsyncCompletedEventPattern<T>(
      Action initialAction,
      object source, string eventName) where T : AsyncCompletedEventArgs
    {
      return (
        Observable.Defer(
          () =>
          {
            var result =

            Observable.Create<T>(
              observer =>
              {
                IDisposable sub =
                  Observable
                    .FromEventPattern<T>(source, eventName)
                    .Subscribe(
                      value =>
                      {
                        if (value.EventArgs.Error != null)
                        {
                          observer.OnError(value.EventArgs.Error);
                        }
                        else if (value.EventArgs.Cancelled)
                        {
                          observer.OnCompleted();
                        }
                        else
                        {
                          observer.OnNext(value.EventArgs);
                        }
                      },
                      ex => observer.OnError(ex),
                      () => observer.OnCompleted());

                return (sub);
              });

            initialAction();

            return (result);
          }));
    }
I’m not at all sure that I got that correct but it allows me to then implement my OnInvokeService method as;
    void OnInvokeService()
    {
      ServiceClient proxy = new ServiceClient();

      var obs =
        FromAsyncCompletedEventPattern<InitialCallCompletedEventArgs>(
          () => proxy.InitialCallAsync(),
          proxy,
          "InitialCallCompleted")
        .SelectMany(result =>
          {
            return (
              FromAsyncCompletedEventPattern<SubsequentCallCompletedEventArgs>(
                () => proxy.SubsequentCallAsync(result.Result),
                proxy,
                "SubsequentCallCompleted"));
          })
        .Select(
          result => result.Result);
       
      obs.Subscribe(
        value => this.DisplayText = value);
    }
which feels fairly “clean” although I daresay there’s a few Rx gremlins lurking in the code I wrote.

Ultimately…

Those networking APIs all surface asynchronously for a reason. Trying to bend them to your evil ways Winking smile is only leading towards a world of pain so I’d recommend the traditional approach or the newer Async/Rx style approaches but, whatever you choose, don’t deliberately go and block that UI thread while the network calls complete.


Posted Mon, Aug 8 2011 3:28 PM by mtaulty

Comments

Steve W wrote re: Silverlight and Synchronous Network Calls
on Mon, Aug 8 2011 9:44 PM

Assuming that the developers know what they are doing, the fact that Silverlight forces you into an asynchronous model for WCF calls is frankly a nuisance. Of course developers coming from an asp.net background or similar who may not be familiar with the potential UI thread blocking issues of a rich client framework like silverlight could really get stuck. So, it's understandable that the async wcf model is there as a default. It would be nice if there was a simple way to turn it off though, as, initially at least, it does make life harder for developers who understand the ramifications of blocking the UI thread - it's really not that hard to spawn a background thread or two to do that type of work and then marshal updates back to the UI thread.

Having said that, I did force myself to learn Rx largely because of the annoyances of the silverlight async wcf model so I don't want to complain too much :) We wrote a large silverlight business app over the last 18 months that relies heavily on Rx. Most of the methods in the service layer return IObservable<TSomethingUseful> which ultimately (after a steepish learning curve and judicious use of extension methods to make wrapping wcf service calls more pleasant...) enabled the writing of very expressive asynchronous code to consume the wcf services. We ended up with a silverlight app layer that was a pleasure to work with, largely thanks to Rx. Even so, an option to do synchronous wcf calls in Silverlight would be a nice addition in my view.

jcoz1968 wrote re: Silverlight and Synchronous Network Calls
on Tue, Aug 9 2011 12:58 AM

Mike, thanks for taking interest in my tweet and especially for writing a blog post about it.

I totally understand MS's reason for going only asynchronous with SL.  If there is one thing I've learned, it's that developers  have a tendency to get lazy including myself, sometimes :), and when end users get a locked UI their probably going to blame Silverlight (or the browser), not the developer.

By the way, the app is OOB, so I sometimes tend to think of it in "Client App" terms, which is no excuse, but bad habits can linger.

Needless to say, in the end I ended up doing everything in the service and learned a whole lot more about multithreading in the process.

Thanks again.

ross wrote re: Silverlight and Synchronous Network Calls
on Tue, Aug 9 2011 6:57 AM

I agree with your sentiments, embrace the inherent async nature of http.

However, how would you approach a scenario where you need to fetch a number of things before proceeding with some operation, but none of the things you are fetching depend on each other.  Chaining all the calls together would introduce unnecessary latency.  For example :

1.  User logs in.

2.  Before showing the main app page / menus, you need to fetch  a) A list of valid menu items for the user.  b) A list of products that relate to the user's country c) A list of something else unrelated.

Chaining A,B and C in sequence might introduce an undesirable latency / lag.

WCF Data Services has a nice feature, which allows you to batch requests.  I wonder if there is a good technique for plain vanilla WCF ?

I would think the locking / threading code might be a little tricky if you want to eliminate the latency of chaining the calls?

mtaulty wrote re: Silverlight and Synchronous Network Calls
on Tue, Aug 9 2011 8:31 AM

Steve W,

I think WCF was just building on what they had available to them in that none of the underlying networking in Silverlight can do synchronous.

It's not too tricky to take the blocking code that I wrote and shuffle it off to some other thread so that it still blocks but doesn't block the UI.

Mike.

mtaulty wrote re: Silverlight and Synchronous Network Calls
on Tue, Aug 9 2011 8:34 AM

jcoz1968,

No worries :-) I think you're dead right that when users see a blocked Silverlight UI they tend to blame Microsoft regardless of what the code might doing :-)

Mike.

mtaulty wrote re: Silverlight and Synchronous Network Calls
on Tue, Aug 9 2011 8:36 AM

ross,

If you don't need to chain the calls because of dependencies between them then you should just be able to kick them all off asynchronously at the same time and either update the UI as they complete individually or simply decrement a counter as they complete and then update the UI when that counter hits 0.

Mike.

Steve W wrote re: Silverlight and Synchronous Network Calls
on Tue, Aug 9 2011 8:39 AM

Ross, you might want to take a look at Rx (System.Reactive) - the scenario you describe is really fairly simple if you wrap your service calls up in IObservable<T> on the Silverlight side. You can then use Observable.ForkJoin to run these calls in parallel and run subsequent code when all the service calls have returned. We've used that technique to run several (around 10) parallel wcf service calls when a silverlight app starts up and then run processing on the results after all have returned. Rx makes this type of synchronisation really simple once you get it integrated into your application.

ross wrote re: Silverlight and Synchronous Network Calls
on Wed, Aug 10 2011 6:11 AM

mike : yes, thanks, I can see that a counter to 0 would work, but I assume you would have to update the counter inside a lock() to avoid race conditions?  Probably not that hard I suppose.

Steve w : interesting.  thanks.  i've played with Rx a bit, but didn't realise it had the ability to synchronise in that manner.  nice.

mtaulty wrote re: Silverlight and Synchronous Network Calls
on Wed, Aug 10 2011 9:53 AM

ross,

It depends. If you're using WCF proxies then I think their use of the Event based Asynchronous Programming model means that they fire completion events on the UI thread.

So, if you decrement your counter in the code that runs on completion then that code runs on a single thread so doesn't need a lock.

If you decrement it somewhere else then you need to do something to protect it.

Mike.

Tom Winans wrote re: Silverlight and Synchronous Network Calls
on Sat, Aug 20 2011 11:15 PM

@SteveW - Agree.

I am happy to have people help me with good frameworks when I develop, but I view the Silverlight "asynchrony only" constraint to be stepping beyond "help" to limit.

I believe that I understand why the SL team has done what it has done, however the approach taken to solve the problem appears to only be from a UI perspective.

What of client side middleware?

Let's take a simple example ... use of Azure/Amazon storage with a relational structure overlayed on it that is managed using relational constructs suitable to handle requests and IO operations from multiple users. Storage operations/services are provisioned by Azure or EC2S3 APIs. File system operations are provisioned using web services hosted elsewhere.

Suppose that the read operation gets file data into a stream, but also requires lookup of some information in the file system services first. These, by necessity in SL, are asynchronous. The actual read of the file itself is aynchronous. AND the wrapping read method has to be ansynchronous because the lower level calls are. Only the read POTENTIALLY is tied to the UI ... more likely, it is tied to an application running in SL that will present something it finds in the file it reads and subsequently processes.

I could avoid some of the asynchrony by making server side methods do some of the work ... but then content from blob storage might have to be delivered to the web service on some server AND THEN be passed on to me. How's that for inefficient?

Synchrony is needed. Service method composition has to be treated as a first class development pattern both on the client and server sides. Whether in a browser or in a richer client application, it is not for a framework to keep me from being stupid. I want the right to be stupid if I choose. If I can lock up my UI thread, then I'll test well enough to find out before someone sees my application in public.