Reputation: 137
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
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