Timo1995
Timo1995

Reputation: 137

Task.ContinueWith() is not executing as expected

Im trying to rewrite some of my old code using async/await and chaining Tasks using ContinueWith() and checking for exceptions with TaskContinuationOptions.NotOnFaulted.

When I debug the code I noticed that it does not run as I expected. Both webrequests are successful but only the first continuation processes the response.

The second continuation does not complete and the last one gives me the result:

Id = 1, Status = RanToCompletion, Method = "{null}", Result = "System.Threading.Tasks.Task`1[System.Threading.Tasks.VoidTaskResult]"

and the result:

Id = 2, Status = WaitingForActivation, Method = "{null}", Result = "{Not yet computed}"

My question is what am I doing wrong and what can I do so the second continuation completes. I am also interested if it is considered good practice to chain tasks together using ContinueWith or if there is a better way to do it without writing a bunch of clumsy methods? Thanks for the help

   using Newtonsoft.Json.Linq;                  

   var api = new Api();
   var order = new Dictionary<string, object>();
   await api.MakeRequest(Api.Endpoint.Orders, HttpMethod.Get, null, "?completed=false&page=" + count)
   //Look for new Orders
   .ContinueWith(ant =>
    {
          dynamic jsonOrder = JObject.Parse(ant.Result);
          JArray data = jsonOrder.data;
          //Process Json Response
          order.Add("customer_name", (string)data[j]["customer_name"]);
          order.Add("product_id", (string)data[j]["product_id"]);
          order.Add("order_id", (string)data[j]["order_id"]);
          order.Add("timestamp", (int)data[j]["timestamp"]);
          //Entries are successfully added
    }, TaskContinuationOptions.NotOnFaulted )
    //Now get more details about the product
    .ContinueWith(async (ant) =>
    {
          string result = await api.MakeRequest(Api.Endpoint.Product, HttpMethod.Get, null, (string)order["product_id"]); 
          //The Request succeeds 

          //This code block does not execute
          dynamic json = JObject.Parse(result);
          order.Add("deadline", (int)json.data.deadline);
          order.Add("price", (string)json.data.price);
          order.Add("amount", (int)json.data.amount);
          //This code block does not execute 

     }, TaskContinuationOptions.NotOnFaulted)
     //Get some more details about the Customer (isRecurring? etc)
     .ContinueWith(async (ant) =>
     {
        //Some more code here
     }

Upvotes: 3

Views: 2734

Answers (1)

NeddySpaghetti
NeddySpaghetti

Reputation: 13495

Like @Ben Robinson said the use of await automatically registers the rest of the method as a continuation which is only executed if the operation succeeds, otherwise an exception is thrown. I'd change my method to remove the ContinueWith calls and consider using ConfigureAwait(false) if you don't need to return to the current SynchrionizationContext after the asynchronous operations are finished, i.e. the rest of the method will continue execution on the thread pool thread. You may also find this article useful.

var api = new Api();
var order = new Dictionary<string, object>();

await api.MakeRequest(Api.Endpoint.Orders, HttpMethod.Get, null, "?completed=false&page=" + count).ConfiugureAwait(false);

//Look for new Orders
dynamic jsonOrder = JObject.Parse(ant.Result);
JArray data = jsonOrder.data;
//Process Json Response
order.Add("customer_name", (string)data[j]["customer_name"]);
order.Add("product_id", (string)data[j]["product_id"]);
order.Add("order_id", (string)data[j]["order_id"]);
order.Add("timestamp", (int)data[j]["timestamp"]);

//Now get more details about the product
string result = await api.MakeRequest(Api.Endpoint.Product, HttpMethod.Get, null, (string)order["product_id"]).ConfiugureAwait(false);

dynamic json = JObject.Parse(result);
order.Add("deadline", (int)json.data.deadline);
order.Add("price", (string)json.data.price);
order.Add("amount", (int)json.data.amount);

Upvotes: 1

Related Questions