-1

So here's what I'm doing:

var resultObj = GetFirstResultAsync()
     .ContinueWith(t => GetSecondResultAsync(resultObj))
     .Wait();

Essentially telling me that I can't use the variable before it's even declared, which I get hence the question I posted. How do I do this?

Here's my goal, I have a list resultObj then on that list I will loop through the Id's to get an array of my another list that I want GetSecondResultAsync kinda drilling down on the list, I wanted to use async since it will be using HttpClient to get the data.

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
PinoyDev
  • 949
  • 1
  • 10
  • 21
  • 2
    It defeats the purpose of writing asynchronous code when you're just going to synchronously block at the end of the operation. – Servy Jan 25 '18 at 19:40
  • 1
    t.Result has what you need – fahadash Jan 25 '18 at 20:52
  • would this be a good solution so I can avoid the "too many request error"? thanks @fahadash – PinoyDev Jan 25 '18 at 21:50
  • 1
    Avoid it altogether and just use `var resultObj = await GetFirstResultAsync(); await GetSecondResultAsync(resultObj);` Reference [Async/Await - Best Practices in Asynchronous Programming](https://msdn.microsoft.com/en-us/magazine/jj991977.aspx) – Nkosi Jan 25 '18 at 23:51
  • I am casting a reopen vote because the question [linked as duplicate](https://stackoverflow.com/questions/7912733/how-to-continuewith-another-function-with-result-from-previous-task-when-using-t) is about invoking a continuation function on the UI thread, while this question is about creating a new task that represents the result of the continuation function. The two questions are related, but not identical IMHO. – Theodor Zoulias Oct 09 '22 at 17:59
  • Somewhat related: [How to convert a Task to a Task?](https://stackoverflow.com/questions/15530099/how-to-convert-a-tasktderived-to-a-tasktbase) – Theodor Zoulias Oct 09 '22 at 18:44

2 Answers2

0

You should be able to pass the result by changing the ContinueWith statement to t.Result. Something like:

var resultObj = GetFirstResultAsync()
 .ContinueWith(t => GetSecondResultAsync(t.Result));

I haven't tested the code.

The first run thread will return a "Task". Which you will have to access by Task.Result. This is what you will have to use.

Edit: As @fahadash stated, "wait()" should not be used. Use "await" instead.

KampfFussel
  • 137
  • 9
  • Let me try this but thank you @KampfFussel – PinoyDev Jan 25 '18 at 21:51
  • The correct way would be to not call `Wait()`, but keep the resultObj as task, and whenever in your code you are ready to use the result, use `await resultObj` – fahadash Jan 25 '18 at 21:57
  • @fahadash that seemed to work, without the wait, any ideas how I can loop through it without hitting 429 (too many request) ? within the "continueWith" like this : ContinueWith(t=> while (true) {GetSecondResultAsync(t.result.id)} – PinoyDev Jan 25 '18 at 22:38
  • 1
    @PinoyDev That sounds like a separate question than about `Task` You seem to be sending too many requests in a small amount of time and server is throttling you. If you are running tasks in a parallel, be sure to set throttle on your end to limit them to certain number at a time – fahadash Jan 25 '18 at 23:32
  • Thanks for pointing that out @fahadash. I updated my answer accordingly. – KampfFussel Jan 26 '18 at 07:54
0

Creating a continuation Task that has a result of different type than the first task, with ContinueWith, is not trivial. You have to use the Unwrap method in order to flatten the resulting Task<Task<MySecondResult>>, handle carefully the failure and cancellation cases, and specify explicitly the TaskScheduler that will execute the continuation:

Task<MySecondResult> task = GetFirstResultAsync().ContinueWith(t =>
{
    if (t.IsFaulted)
    {
        var tcs = new TaskCompletionSource<MySecondResult>();
        tcs.SetException(t.Exception.InnerExceptions);
        return tcs.Task;
    }
    if (t.IsCanceled)
    {
        TaskCompletionSource<MySecondResult> tcs = new();
        tcs.SetCanceled(new TaskCanceledException(t).CancellationToken);
        return tcs.Task;
    }
    return GetSecondResultAsync(t.Result);
}, TaskScheduler.Default).Unwrap();

This is quite cumbersome. You don't want to have code like this appear frequently in your application code. You can either encapsulate this functionality in an extension method, like the Then/ContinueWithResult extension method requested in this GitHub proposal, or use async/await instead of the ContinueWith. Async/await is composable, so you can write a third async method that combines the GetFirstResultAsync and the GetSecondResultAsync to one:

async Task<MySecondResult> GetSecondAfterFirstAsync()
{
    MyFirstResult result = await GetFirstResultAsync();
    return await GetSecondResultAsync(result);
}
Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104