Debugging Fun with the Async CTP

I was writing a short talk about the Async CTP and as part of that, I wrote this little WPF form which goes off to my local web server to grab an image and display it;

image produces image

when you click on the “Get Image” button that that image is just served up by my local web server and accessed with an HTTP GET.

The code for that looks something like this where OnGetImage is the event handler for the button on the screen;

namespace TaskPlayground
{
  using System.IO;
  using System.Net;
  using System.Windows;
  using System.Windows.Media.Imaging;

  public partial class MainWindow : Window
  {
    static readonly string url = "http://localhost/photo1.jpg";

    public MainWindow()
    {
      InitializeComponent();
    }
    void OnGetImage(object sender, RoutedEventArgs e)
    {
      OnGetImageInternal();
    }
    async void OnGetImageInternal()
    {
      WebClient client = new WebClient();
      byte[] bits = await client.DownloadDataTaskAsync(url);
      FillInPicture(new MemoryStream(bits));
    }
    void FillInPicture(MemoryStream stream)
    {
      stream.Seek(0, SeekOrigin.Begin);
      BitmapImage bitmapImage = new BitmapImage();
      bitmapImage.BeginInit();
      bitmapImage.StreamSource = stream;
      bitmapImage.EndInit();
      this.image1.Source = bitmapImage;
    }
  }
}

but what I thought really highlighted the workings of things was the debugging experience in that if I go add some “breakpoints”;

    void OnGetImage(object sender, RoutedEventArgs e)
    {
      OnGetImageInternal();
      // Breakpoint 1.
      Debugger.Break();
    }
    async void OnGetImageInternal()
    {
      WebClient client = new WebClient();
      byte[] bits = await client.DownloadDataTaskAsync(url);

      // Breakpoint 2.
      Debugger.Break();
      FillInPicture(new MemoryStream(bits));
    }

Then I think most (all?) .NET developers prior to the Async CTP would have been quite happy to borrow money in order to bet that breakpoint 2 would fire before breakpoint 1 and then they’d have retired to a desert island somewhere Smile 

This is the natural order of things. It’s what we intuitively “know”.

Of course, with the Async CTP “everything you know is wrong” because breakpoint 1 fires before breakpoint 2 and, even more surprisingly if you’ve not been following this stuff too closely is that my debugger’s threading window shows me that breakpoint 1 runs on my main thread;

image

and that breakpoint 2 also runs on my main thread;

image

That is ( as I talked about in previous posts and is covered very well elsewhere ) the async CTP work is SynchronizationContext aware and I think that you can see that from the callstacks here although I’m not 100% certain that I’m looking at the right frames as they get a bit “deep” in their interactions with the WPF Dispatcher in this case;

image

"We’re not in Kansas any more” has become my stock phrase of late – this is not your father’s C# ( or VB for that matter ) Winking smile

If you want to get this from “the horse’s mouth” then, of course, you should go watch the talk that Anders gave at BUILD ( make sure that you watch the Smooth Streaming format version at full screen rather than the default version which doesn’t smooth stream and gives you a slightly more shabby experience );

Visual Studio Async CTP–Simple Examples in ‘Quiz’ Form

This one’s just a bit of “fun” for a Friday afternoon ( depending on how you define “fun” Winking smile ).

I was writing some asynchronous code yesterday in JavaScript and I then had cause to duplicate it in .NET using the await support of the Async CTP which I’ve tried to write about before ( generally and combined with Rx ).

This led into a debate with a colleague where we started passing bits of code backwards and forwards and got down to some simple cases and I thought I’d share here in the form of a “quiz” Confused smile

This isn’t meant to be even slightly comprehensive, it’s just that I found that we tended to start with small, simple examples and then build them up a little and so I thought I’d re-use some of those pieces of code here.

So…roll up and see how many points you can score with a few quiz questions on the async CTP.

Before we get going…

Before we start – I’m using TaskEx.Delay here and you might have the async CTP but you might not have seen TaskEx.Delay so I’ll say from the docs that it;

Starts a Task that will complete after the specified due time.”

the bolding is mine because I think it’s vital to know that it starts a task rather than just creates one.

Note that there are no “trick” questions with the exception of question 2 which is just nasty.

and we’re not quite ready yet…

We create some tasks here which will need assigning to threads in order to run them – that introduces an element of non-determinism (e.g. the threadpool can pretty much do whatever it likes) so where I’m saying “how long does this piece of code take to run” I’m really saying “how long does it take to run given that the scheduler does more or less what you’d expect it to”).

This introduces an element of non-determinism into the quiz Winking smile

Now…on with the quiz;

Question 1 ( 5 points )

(Approximately) how many seconds will this program print to the console?

using System;
using System.Diagnostics;
using System.Threading.Tasks;

class Program
{
  static void Main(string[] args)
  {
    Stopwatch sw = new Stopwatch();
    sw.Start();

    TaskEx.Delay(TimeSpan.FromSeconds(3));

    sw.Stop();
    Console.WriteLine("The program took {0} seconds", sw.Elapsed.Seconds);

  }
}

Question 2 ( 20 points )

Again, approximately how many seconds will this program print to the console?

using System;
using System.Diagnostics;
using System.Threading.Tasks;

class Program
{
  static async void Main(string[] args)
  {
    Stopwatch sw = new Stopwatch();
    sw.Start();

    await TaskEx.Delay(TimeSpan.FromSeconds(3));

    sw.Stop();
    Console.WriteLine("The program took {0} seconds", sw.Elapsed.Seconds);
  }
}

Question 3 ( 5 points )

Ok, I apologise for the last question, that was really nasty. Let’s get back onto more reasonable ground here with a better class of question. What about this one?

using System;
using System.Diagnostics;
using System.Threading.Tasks;

class Program
{
  static void Main(string[] args)
  {
    Stopwatch sw = new Stopwatch();
    sw.Start();

    TaskEx.Delay(TimeSpan.FromSeconds(3)).Wait();

    sw.Stop();
    Console.WriteLine("The program took {0} seconds", sw.Elapsed.Seconds);
  }
}

Question 4 ( 5 points )

And, to rebuild more trust in the pillock setting the questions Winking smile here’s a similar situation,  what will this one print?

using System;
using System.Diagnostics;
using System.Threading.Tasks;

class Program
{
  static void Main(string[] args)
  {
    Stopwatch sw = new Stopwatch();
    sw.Start();

    Foo().Wait();

    sw.Stop();
    Console.WriteLine("The program took {0} seconds", sw.Elapsed.Seconds);
  }
  static async Task Foo()
  {
    await TaskEx.Delay(TimeSpan.FromSeconds(3));
  }
}

Question 5 ( 10 points )

Just to check that you’re still with me, looking at the code example below and the assertions within it, which of the assertions will fail and throw a big, nasty dialog to the screen?

using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

class Program
{
  static int threadId;

  static void Main(string[] args)
  {
    Stopwatch sw = new Stopwatch();
    sw.Start();

    threadId = Thread.CurrentThread.ManagedThreadId;

    Foo().Wait();

    sw.Stop();
    Console.WriteLine("The program took {0} seconds", sw.Elapsed.Seconds);
  }
  static async Task Foo()
  {
    Debug.Assert(Thread.CurrentThread.ManagedThreadId == threadId);

    await TaskEx.Delay(TimeSpan.FromSeconds(3));

    Debug.Assert(Thread.CurrentThread.ManagedThreadId == threadId);
  }
}

Possible Answers ( these would be a,b,c if I could get Live Writer to do it Smile )

  1. The one on line 24.
  2. The one one line 28.
  3. Both of the ones on line 24 and on line 28.
  4. None of them.
  5. I’m still not talking to you after question number 2. That was a really nasty thing to put so early in the quiz.

Question 6 ( 5 points )

Back from the leisures of multiple choice answers to working out timings – how long will this one print to the console?

using System;
using System.Diagnostics;
using System.Threading.Tasks;

class Program
{
  static void Main(string[] args)
  {
    Stopwatch sw = new Stopwatch();
    sw.Start();

    Foo().Wait();

    sw.Stop();
    Console.WriteLine("The program took {0} seconds", sw.Elapsed.Seconds);
  }
  static async Task Foo()
  {
    await TaskEx.Delay(TimeSpan.FromSeconds(3));
    await TaskEx.Delay(TimeSpan.FromSeconds(2));
  }
}

Question 7 ( 10 points )

And we’re still stuck in the world of timings, what about this one?

using System;
using System.Diagnostics;
using System.Threading.Tasks;

class Program
{
  static void Main(string[] args)
  {
    Stopwatch sw = new Stopwatch();
    sw.Start();

    Foo().Wait();

    sw.Stop();
    Console.WriteLine("The program took {0} seconds", sw.Elapsed.Seconds);
  }
  static async Task Foo()
  {
    for (int i = 0; i < 3; i++)
    {
      await TaskEx.Delay(TimeSpan.FromSeconds(3));
      await TaskEx.Delay(TimeSpan.FromSeconds(2));
    }
  }
}

Question 8 ( 10 points )

Starting to act a little differently;

using System;
using System.Diagnostics;
using System.Threading.Tasks;

class Program
{
  static void Main(string[] args)
  {
    Stopwatch sw = new Stopwatch();
    sw.Start();

    Foo().Wait();

    sw.Stop();
    Console.WriteLine("The program took {0} seconds", sw.Elapsed.Seconds);
  }
  static async Task Foo()
  {
    await TaskEx.WhenAll(
      TaskEx.Delay(TimeSpan.FromSeconds(3)),
      TaskEx.Delay(TimeSpan.FromSeconds(2)));
  }
}

Question 9 ( 5 points )

Very similar;

using System;
using System.Diagnostics;
using System.Threading.Tasks;

class Program
{
  static void Main(string[] args)
  {
    Stopwatch sw = new Stopwatch();
    sw.Start();

    Foo().Wait();

    sw.Stop();
    Console.WriteLine("The program took {0} seconds", sw.Elapsed.Seconds);
  }
  static async Task Foo()
  {
    await TaskEx.WhenAny(
      TaskEx.Delay(TimeSpan.FromSeconds(3)),
      TaskEx.Delay(TimeSpan.FromSeconds(2)));
  }
}

Question 10 ( 10 points )

Back to loops;

using System;
using System.Diagnostics;
using System.Threading.Tasks;

class Program
{
  static void Main(string[] args)
  {
    Stopwatch sw = new Stopwatch();
    sw.Start();

    Foo().Wait();

    sw.Stop();
    Console.WriteLine("The program took {0} seconds", sw.Elapsed.Seconds);
  }
  static async Task Foo()
  {
    for (int i = 0; i < 3; i++)
    {
      await TaskEx.WhenAny(
        TaskEx.Delay(TimeSpan.FromSeconds(3)),
        TaskEx.Delay(TimeSpan.FromSeconds(2)));
    }
  }
}

Question 11 ( 15 points )

We’re still with loops but we’re being a little bit more sneaky

using System;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Collections.Generic;

class Program
{
  static void Main(string[] args)
  {
    Stopwatch sw = new Stopwatch();
    sw.Start();

    Foo().Wait();

    sw.Stop();
    Console.WriteLine("The program took {0} seconds", sw.Elapsed.Seconds);
  }
  static async Task Foo()
  {
    List<Task> tasks = new List<Task>();

    for (int i = 0; i < 3; i++)
    {
      tasks.Add(TaskEx.Delay(TimeSpan.FromSeconds(3)));
      tasks.Add(TaskEx.Delay(TimeSpan.FromSeconds(2)));
    }
    await TaskEx.WhenAll(tasks);
  }
}

 

and 11 is where I ran out of steam without wandering away from TaskEx.Delay and into other territory.

Answers ( I think )

I think these are the answers (with a little bit of explanation);

  1. Answer is 0 seconds. There’s no code that waits for anything so it’s just going to start that task and then stop the stopwatch straight away. 5 points.
  2. Answer is “this example doesn’t print anything”. Try it. This is to do with trying to be async inside of main and there’s a thread up at the forums that talks about it. Sorry. Trick question. Nasty. 20 points and if you knew this already then you’ve been there before.
  3. Answer is 3 seconds. We create a Task that delays for 3 seconds and we wait for it. 5 points.
  4. Answer is 3 seconds. This is really the same as question 3 with some more thrown in. 5 points.
  5. Answer is option 2 – the assertion on line 28. When the await completes, some thread has to call the “callback” to continue the work here and it can’t be our main thread because it’s blocked in a call to Wait() so it has to be another thread. Note – in other scenarios where there’s a synchronization context in play, this might be different. 5 points.
  6. Answer is 5 seconds – we first wait for 3 seconds and then for 2 seconds so that’s 5. 5 points.
  7. Answer is 15 seconds – we loop around 3 times waiting for 3 and then 2 seconds so that’s 15. 10 points.
  8. Answer is 3 seconds. We have 2 waits to wait for and the longest is 3. 5 points.
  9. Answer is 2 seconds. We wait for the first wait and the shorted is 2. 5 points.
  10. Answer is 6 seconds. We loop 3 times over the previous scenario doing an await each time so that means 6 seconds. 10 points.
  11. Answer is 3 seconds. We make 6 separate tasks with the longest taking 3 seconds and they all (probably!!!!) run concurrently and then we wait for all of them. 15 points.

Scores

I think there are 90 points up for grabs there so if you managed to genuinely get 50+ I think you’re doing pretty well and have perhaps seen some of this stuff before or played with it.

If you managed 90 then you can feel very proud of yourself.

If you got 0 then you’ve perhaps got some reading to do or perhaps were searching the web for “a sink CTP” and were looking for “Copper Sinks – CTP Systems” – in that case, I can only apologise Winking smile

Silverlight and Synchronous Network Calls

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.