John
John

Reputation: 439

Multiple Asynchronous Task execution

Please bear with me :-)

I'm struggling with the TPL in c# and am stuck trying to figure out the best way to design a solution for kicking off multiple async tasks, waiting for them to complete, and moving on. My initial POC is below. Each IDataGatherer instance needs to get the data and massage it into a DataObject instance.

  1. I'm unsure of how to handle the continuation from the DownloadStringTaskAsync call such that I can take the result and massage it into a DataObject. ContinueWith wants to be provided a method with void return signature but I feel like the ExtractData method needs to return a Task instance or else I don't have a Task instance to return from the GetDataAsync() method.

  2. I'm also wondering if I need to introduce a TaskCompletionSource in my IDataGatherer instances but how do I hitch that onto the task(s) that are doing the real work - DownloadstringTaskAsync and ExtractData for example?

interface IDataGatherer
{
    Task<DataObject> GetDataAsync();
}

class DataObject
{
    public string Data { get; set; }
}

class IpGatherer : IDataGatherer
{
    private readonly string _url = "http://ip.jsontest.com";

    public Task<DataObject> GetDataAsync()
    {
        var tcs = new TaskCompletionSource<DataObject>(); // Do I need this???

        var client = new WebClient();

        // stuck here
        var task = client.DownloadStringTaskAsync(_url).ContinueWith(ExtractData);
    }

    private void ExtractData(Task<string> obj)
    {

    }
}

class Program
{
    private static void Main(string[] args)
    {
        // takes a list of IDataGatherers and waits for them
        // all to complete, handles exceptions, etc.
    }
}

Designing the solution this way may be over-complicating things so I'm open to suggestions to clean things up or do them more succinctly.

I'm using .NET 4.5

Upvotes: 0

Views: 617

Answers (1)

svick
svick

Reputation: 244757

First, you don't need TaskCompletionSource. That's because ContinueWith() can be provided with a method with non-void signature. E.g.:

public Task<DataObject> GetDataAsync()
{
    var client = new WebClient();

    return client.DownloadStringTaskAsync(_url)
                 .ContinueWith((Func<Task<string>, DataObject>)ExtractData);
}

private DataObject ExtractData(Task<string> task)
{
    return new DataObject(task.Result);
}

(Using Result won't block, because you can be certain the Task will be completed at that point.)

But since you're using DownloadStringTaskAsync(), you're likely on .Net 4.5, which means you can use await. That makes the code even simpler:

public async Task<DataObject> GetDataAsync()
{
    var client = new WebClient();

    var s = await client.DownloadStringTaskAsync(_url);
    return ExtractData(s);
}

private DataObject ExtractData(string s)
{
    return new DataObject(s);
}

Upvotes: 2

Related Questions