views:

231

answers:

2

When invoking a WCF service asynchronous there seems to be two ways it can be done.

1.

WcfClient _client = new WcfClient();    
public void One()
{
    _client.BegindoSearch("input", ResultOne, null);
}

private void ResultOne(IAsyncResult ar)
{
    string data = _client.EnddoSearch(ar);
}

2.

public void Two()
{
    WcfClient client = new WcfClient();
    client.doSearchCompleted += TwoCompleted;
    client.doSearchAsync("input");
}

void TwoCompleted(object sender, doSearchCompletedEventArgs e)
{
    string data = e.Result;
}

And with the new Task<T> class we have an easy third way by wrapping the synchronous operation in a task.

3.

public void Three()
{
    WcfClient client = new WcfClient();
    var task = Task<string>.Factory.StartNew(() => client.doSearch("input"));
    string data = task.Result;
}

They all give you the ability to execute other code while you wait for the result, but I think Task<T> gives better control on what you execute before or after the result is retrieved.

Are there any advantages or disadvantages to using one over the other? Or scenarios where one way of doing it is more preferable?

+2  A: 

I would not use the final version because it will run the operation on a worker thread instead of an I/O thread. This is especially bad if you're doing it inside ASP.NET, where the worker threads are needed to serve requests. Not to mention, you're still blocking on the main thread waiting for the task to finish when you check its Result, so technically you're wasting two worker threads, or one worker and the UI.

The BeginXYZ and XyzAsync methods for WCF clients work essentially the same way - you should choose the appropriate version based on the use case you want to support (either APC or event-driven, respectively). For example, the BeginXyz version would (perhaps counterintuitively) be easier to use within an ASP.NET (or MVC) async page, whereas the XyzAsync version would be easier to use in a Windows Form.

Aaronaught
The Worker vs IO thread aspect is interesting. I know the thread pool has a fixed amount of each one and that you can change them. But what's the difference between a worker thread and IO thread in the framework. I assume it's more than just semantics.
Mikael Svenson
@Mikael: I/O threads are designed for long waiting periods; they basically go to sleep and wait for the I/O system to wake them back up with an interrupt. Worker threads are intended for CPU-heavy work, and you don't want to waste them on blocking synchronous I/O calls.
Aaronaught
there's some more information in this MSDN article about tasks with respect to worker threads - http://msdn.microsoft.com/en-us/magazine/ff959203.aspx - also a good background (kind of a history lesson) about the different async methods available in .NET
Simon_Weaver
+1  A: 

There's a problem with your first example. You should certainly not be creating a new WcfClient instance when you call EndDoSearch. You should either keep the original instance around in a field or pass it as the state parameter.

But in general, I prefer option #1 because it makes it very easy to use an anonymous method to handle the result.

var client = new WcfClient();
client.BeginDoSearch("input", ar => {

    var result = client.EndDoSearch(ar);
    // blah blah

}, null);
Josh Einstein
Good catch on that; mind you, it's iffy to be creating WCF clients on-the-fly *period* - usually these end up being singletons/per-session or managed by a DI container.
Aaronaught
@Josh, I know I should be using the same client, and have corrected it now :)
Mikael Svenson