Reputation: 439
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.
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.
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
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