Using Rx to consume a Task based WCF service by ThinqLinq

Using Rx to consume a Task based WCF service

Among the many changes that Dev 11 brings is the new default when adding a service reference to generate Task based proxy methods rather than using the APM flavor (using the BeginXXX – EndXXX model). In this post, we’ll look at creating a simple service and then consuming it using the Reactive Extensions. Let’s start by defining the service interface and implementation:

Imports System.ServiceModel
Imports System.Threading 

<ServiceContract()>
Public Interface ISimpleServicesvc

    <OperationContract()>
    Function DoSomethingCool(input As String) As String

End Interface

Public Class SimpleServicesvc
    Implements ISimpleServicesvc

    Public Function DoSomethingCool(input As String) As String Implements ISimpleServicesvc.DoSomethingCool
        Return (String.Join("", From letter In input.ToCharArray()
               Order By letter
               Distinct))
    End Function

End Class

Essentially here we are just taking a string input and returning the distinct characters sorted. The details of the service in this case are trivial. Our focus here is how to implement the service client. We start by adding a service reference in our client application by right clicking on the project and selecting Add Service Reference. (Alternatively, you can now press Ctrl-Q and request to “Add Service Reference” from there. From the dialog, you can still use the “Discover” button to locate the service as long as it is in your solution.

image

One thing to note is that the proxy classes are now by default generated using Task based methods rather than the previous IAsyncResult AMP method.

image

As a result, the definition of the proxy class is as follows:

Public Function DoSomethingCoolAsync(ByVal input As String) 
                 As System.Threading.Tasks.Task(Of String) 
                 Implements SimpleService.ISimpleServicesvc.DoSomethingCoolAsync
    Return MyBase.Channel.DoSomethingCoolAsync(input)
End Function

If we wanted to consume this using the new Async/Await, we could do it as follows:

Private Async Sub SubmitClicked() Handles SubmitButton.Click
   Dim svc = New SimpleService.SimpleServicesvcClient()
   Dim req = Await svc.DoSomethingCoolAsync(InputText.Text)
   OutputText.Text = req
End Sub

Of course, to put the LINQ spin on this, let’s see the Rx version to do the same thing:

Private Async Sub SubmitClicked() Handles SubmitButton.Click
    Dim svc = New SimpleService.SimpleServicesvcClient()
    Dim req = svc.DoSomethingCoolAsync(InputText.Text).ToObservable()
    req.ObserveOnDispatcher().Subscribe(Sub(val) OutputText.Text = val)
End Sub

We start by turning the Task into an Observable producer using the ToObservable extension method. We then subscribe to the observable making sure to return back to the dispatcher thread because the task based service is run on a taskpool thread. Of course in this case, we are subscribing on every button click. With Rx, we could wire the button click and service request up on form navigate and unwire it when navigating from the form as follows:

Private requestDisposable As IDisposable
Protected Overrides Sub OnNavigatedTo(e As Navigation.NavigationEventArgs)
    Dim svc = New SimpleService.SimpleServicesvcClient

    requestDisposable = (From click In Observable.FromEventPattern(Of RoutedEventArgs)(SubmitButton, "Click")
                        From req In svc.DoSomethingCoolAsync(InputText.Text).ToObservable()
                        Select req).
                        ObserveOnDispatcher().
                        Subscribe(Sub(val) OutputText.Text = val)
End Sub
Protected Overrides Sub OnNavigatedFrom(e As Navigation.NavigationEventArgs)
    MyBase.OnNavigatedFrom(e)
    requestDisposable.Dispose()
    requestDisposable = Nothing
End Sub
Posted on - Comment
Categories: WCF - Rx - VB Dev Center -
comments powered by Disqus