Working with WCF and task-based operations

I'm trying to make it possible for a client to make several searches at the same time without it affecting the response time of the seach page. To do this i was hoping to use .NET 4.5's task-based operations in WCF but I'm having troubles understanding the logic.

What I want my end result to be is to do multiple calls to the WCF API and then merge these into one big result and order it by each search items relevence.

This is how my code looks like today:

public partial class WebForm1 : System.Web.UI.Page
{
    private static SwepubSearchServiceClient _client;
    private static List<SearchItem> _searchItems = new List<SearchItem>(); 
    protected void Page_Load(object sender, EventArgs e)
    {
        _client = new SwepubSearchServiceClient();

        var result1 = GetAsyncSearchItems("query1", "subQuery1");
        var result2 = GetAsyncSearchItems("query2", "subQuery2");
        var result3 = GetAsyncSearchItems("query3", "subQuery3");

        // What to do here?

    }

    private static async Task<SearchItem[]> GetAsyncSearchItems(string query = "", string subQuery = "")
    {
        var task = _client.DoSearchSimpleAsync(query, subQuery);
        return await task;
    }
}

Basicly, what I need to know is what to do with each result (result1, result2, result3) after i get them back. I though i was going to be able to call result1.Result after each method call but by then they aren't yet computed so it won't do any good.

While I was trying stuff before my GetAsyncSearchItems method looked something like this:

private static async void GetAsyncSearchItems()
    {
        var task1 = _client.DoSearchSimpleAsync("query1", "subQuery1");
        var task2 = _client.DoSearchSimpleAsync("query2", "subQuery2");
        var task3 = _client.DoSearchSimpleAsync("query3", "subQuery3");

        var result1 = await task1;
        var date1 = DateTime.Now.TimeOfDay;
        var result2 = await task2;
        var date2 = DateTime.Now.TimeOfDay;
        var result3 = await task3;
        var date3 = DateTime.Now.TimeOfDay;

        var list = new List<SearchItem>();
        list.AddRange(result1);
        list.AddRange(result2);
        list.AddRange(result3);
    }

When i did this i was able to retrieve the result in the list object but I wasn't able to return it to my Page_Load since async method can only return void, Task or Task so it was of no use. Or am I misunderstanding something? Should I work inside the static method with the result?

I'm probobly missing something basic here but I'm hoping someone can stear me in the right direction. I would really apreachiate it!

Upvotes: 0

Views: 1099

Answers (4)

Stephen Cleary
Stephen Cleary

Reputation: 457197

Your GetAsyncSearchItems method should look like this (following the Task-based Asynchronous Pattern):

private static async Task<List<SearchItem>> GetSearchItemsAsync()
{
    var task1 = _client.DoSearchSimpleAsync("query1", "subQuery1");
    var task2 = _client.DoSearchSimpleAsync("query2", "subQuery2");
    var task3 = _client.DoSearchSimpleAsync("query3", "subQuery3");

    var results = await Task.WhenAll(task1, task2, task3);

    var list = new List<SearchItem>();
    list.AddRange(results[0]);
    list.AddRange(results[1]);
    list.AddRange(results[2]);
    return list;
}

Once you have that method, you can write Page_Load as such:

protected async void Page_Load(object sender, EventArgs e)
{
    _client = new SwepubSearchServiceClient();
    var results = await GetSearchItemsAsync();
    ...
}

While async void works in this scenario, the ASP.NET team prefers you use RegisterAsyncTask, as such:

protected void Page_Load(object sender, EventArgs e)
{
    _client = new SwepubSearchServiceClient();
    RegisterAsyncTask(new PageAsyncTask(PageLoadAsync));
}

private async Task PageLoadAsync()
{
    var results = await GetSearchItemsAsync();
    ...
}

You may find my async intro helpful.

Upvotes: 0

sinelaw
sinelaw

Reputation: 16563

The ".NET 4.5 way" of doing it, as discussed in this Q&A, is to make your Page_Load method async. Then you can call your async method, and ASP.NET will do the rest towards the client:

protected async void Page_Load(object sender, EventArgs e)
{
    ...
    var results = await GetAsyncSearchItems(...)
    ... do something with the results
}

private static async SearchItem[] GetAsyncSearchItems()
{
    ... await stuff
    return list;
}

More resources:

Upvotes: 1

Shulhi Sapli
Shulhi Sapli

Reputation: 2476

You can do it like this:

    var task1 = _client.DoSearchSimpleAsync("query1", "subQuery1");
    var task2 = _client.DoSearchSimpleAsync("query2", "subQuery2");
    var task3 = _client.DoSearchSimpleAsync("query3", "subQuery3");

    await Task.WhenAll(task1, task2, task3);

    var result1 = task1.Result;
    var date1 = DateTime.Now.TimeOfDay;
    var result2 = task2.Result;
    var date2 = DateTime.Now.TimeOfDay;
    var result3 = task3.Result;
    var date3 = DateTime.Now.TimeOfDay;

Upvotes: 1

Justin Harvey
Justin Harvey

Reputation: 14682

You need to add your three results, result1, result2 and result3 to an array of Tasks.

Then you can do this:

Task.WaitAll(tasks);

where tasks is the array.

http://msdn.microsoft.com/en-us/library/dd270695(v=vs.110).aspx

After the WaitAll completes, you can retrieve the lists of SearchItems from each task.

Upvotes: 0

Related Questions