Using F#’s async workflows to invoke a WCF service

In addition to Ted Neward’s posts on creating a WCF service in F# I’d like to share a howto on calling a WCF service asynchronously from F# using the infamous async workflows.
 
I’ll start off with a simple data contract. This is not required, you could use only primitive type parameters, but I like data contracts. The easiest way is to create a record type. Unfortunately the serializer requires mutable fields, but I can live with that. Please note I’m skipping the open System.Runtime.Serialization and open System.ServiceModel.
 

[<DataContract>]
type public MyRequest = {
    [<DataMember>]
    mutable MyParameter:string;
}

[<DataContract>]

type public MyResult = {
    [<DataMember>]
    mutable MyResultParameter:string;
}

Then I’ll define an interface for my service in F#:

[<ServiceContract>]

type public IMyService =
    [<OperationContract>]
    abstract MyOperation: Request:MyRequest -> MyResult

Now to invoke a service asynchronously I need to create a new interface with a slightly different signature. For WCF this new interface is equivalent to the one above, except that it allows asynchronous invocation. Because they need to have the same name I put them in a different assembly so I have one assembly for the contract at the server side and another assembly for the client side. We can reuse the data contract though.

[<ServiceContract>]

type public IMyService =
    [<OperationContract>]
    abstract MyOperation: Request:MyRequest -> MyResult
    [<OperationContract(AsyncPattern =
true)>]
    abstract BeginMyOperation: Request:MyRequest * AsyncCallback * obj -> IAsyncResult
    abstract EndMyOperation: IAsyncResult -> MyResult

Notice the Begin… and End… methods. By adding the AsyncPattern = true to the OperationContract WCF assumes that it’s the asynchronous version of MyOperation. As you can see the signature is slightly different: BeginMyOperation expects an additional callback delegate and an optional state object and returns a ‘handle’ that is passed to EndMyOperation to get the result of invoking MyOperation.

Note that here too I need to supply a name for the first parameter, in this case ‘Request’. As Ted described WCF requires a name for the parameters specified in the interface definition. This is common in C# and VB so that’s probably the reason why it wasn’t noticed by the WCF team. Luckily it’s easy to add in F#.

The above code is enough to invoke a service asynchronously. But if we want to use it in async workflows we require another method named AsyncMyOperation. I decided to create an extension method that adds this method to the interface we just created:

module

public Async =
    type IMyService with
    member s.AsyncMyOperation(request) =
        Async.BuildPrimitive(request, s.BeginMyOperation, s.EndMyOperation)

Essentially I’m creating a new method named AsyncMyOperation by calling Async.BuildPrimitive. Async.BuildPrimitive requires the Begin… and End… methods that are common in the .NET Framework for asynchronous operations. It then creates an Async<‘a> that we can use in an async workflow. UPDATE: I previously created a local function to capture the request and handed that to Async.BuildPrimitive but I just noticed the overloads of BuildPrimitive that take additional arguments. You can supply up to three arguments. When you need to pass more (unlikely I’d say) you can always create a local function to capture additional arguments.

Mind you, the module name I’m using in the code above really doesn’t matter as long as you add an open Async where you want to use it.

Right, now all we need to do is to create the async workflow to actually invoke the service:

let CallMyService =
    async {
        let request = { MyParameter = "Test" }
        use factory = new ChannelFactory<IMyService>(new BasicHttpBinding(), new EndpointAddress("http://localhost:12345/MyService.svc&quot;))
        let channel = factory.CreateChannel()
       
let! result = channel.AsyncMyOperation(request)
        printf "%A" result.MyResultParameter
   
}

Please notice the exclamation mark in let! result = … If you add a Debug.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString()) before and after the call you’ll see that the code below the service call runs on a different thread than the lines above it.

Then, finally, you can run your async workflow with Async.Spawn CallMyService. You can use Async.Run but it would still block to wait for the result so that’s probably not what you want.

Well, please let me know if this code works for you or not or any comments and questions you might have.

Advertisements

2 thoughts on “Using F#’s async workflows to invoke a WCF service

  1. I guess you should use "use factory = …." instead of "let factory = …" also possible that you need IDisposable handling for other expressions…

    Like

  2. Ah, yes. Excellent point Mike, thanks. I\’ve updated the code. Come to think of it, that\’s actually a great advantage of async workflows. All the code is in a single scope, even though it switches threads, so no need to dispose separately.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s