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?
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.
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With