Reputation: 2586
Folks, I'm finding myself in a weird situation. I need to chain tasks of different returning types together. Normally, you can do something like this
Task<T> t = Task<T>.Factory.StartNew(() => ... some T instance);
Task t2 = t.ContinueWith<U>(parent => ...);
return Task.WhenAll(t, t2);
My complication however, lies in using the FromAsync
helper method to wrap a Begin/End pair and convert that into a Task. I'm trying to write an asynchronous client using HttpWebRequest and tasks on .NET 4.0 (so await is not an option).
My problem is that the return type of FromAsync
is a Task itself which prevents me from using it in a ContinueWith
method (ContinueWith
expects the return type and wraps the data itself in a Task
object).
Here is the code I have so far, which yields the correct functional result, but is not truly asynchronous:
public Task<string> GetHttpRequest(string url, string contentType)
{
var httpWebRequest = CreateHttpWebRequest(url, "GET", contentType);
Task<WebResponse> httpTask = Task.Factory.FromAsync<WebResponse>(httpWebRequest.BeginGetResponse, httpWebRequest.EndGetResponse, null);
return httpTask.ContinueWith(httpAntecedent =>
{
WebResponse webResponse = httpAntecedent.Result;
Stream responseStream = webResponse.GetResponseStream();
byte[] data = new byte[webResponse.ContentLength];
var streamReadTask = Task<int>.Factory.FromAsync(responseStream.BeginRead, responseStream.EndRead, data, 0, data.Length, TaskCreationOptions.AttachedToParent);
return streamReadTask.ContinueWith(parent =>
{
responseStream.Close();
webResponse.Close();
return Encoding.UTF8.GetString(data);
});
}).Result;
}
Upvotes: 1
Views: 537
Reputation: 244928
To rephrase your question, you have Task<Task<string>>
and you want to get Task<string>
from that, without synchronously waiting for the Task
to complete.
In C# 5.0, you could do this by using double await
: return await await task;
.
Without C# 5.0, you can use Unwrap()
, it does exactly what you want: return task.Unwrap();
.
If, for some reason, you wanted to do this by yourself, you could use ContinueWith()
inside ContinueWith()
together with TaskCompletionSource
.
But your code is flawed: it assumes that you will get the whole response in a single read. That's not guaranteed at all, and in fact won't work correctly quite often. Doing this properly would require more complicated code and probably also TaskCompletionSource
.
Upvotes: 3