Code is bypassing await and not stoppping for api to complete

170 views Asked by At

In reference to my previous question,I made the necessary changes but still my code was giving blank data.So ,I created a poc but this is having some issue(blank data as output). I can see json output on browsing 'http://localhost:50193/api/people'

On Debugging,I found below information.

Error in POC; Status=Waiting or activation. Method="null" Result-Not yet Computed.

Also,program is exiting on HttpResponseMessage response = await client.GetAsync("api/people"); so I can not debug further.

Person.cs

using System;

namespace CoreTaskApp
{    
    public class Person
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public DateTime StartDate { get; set; }
        public int Rating { get; set; }

        public override string ToString()
        {
            return string.Format("{0} {1}", FirstName, LastName);
        }
    }
}

PersonRepository.cs

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace CoreTaskApp
{
    public class PersonRepository
    {
        HttpClient client = new HttpClient();

        public PersonRepository()
        {
            client.BaseAddress = new Uri("http://localhost:50193/");
            client.DefaultRequestHeaders.Accept.Add(
                new MediaTypeWithQualityHeaderValue("application/json"));
        }

        public async Task<List<Person>> GetAsync()
        {
            await Task.Delay(3000);

            //cancellationToken.ThrowIfCancellationRequested();

            HttpResponseMessage response = await client.GetAsync("api/people");
            if (response.IsSuccessStatusCode)
            {
                var stringResult = await response.Content.ReadAsStringAsync();
                return JsonConvert.DeserializeObject<List<Person>>(stringResult);
            }
            return new List<Person>();
        }
    }
}

Program.cs

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace CoreTaskApp
{
    class Program
    {
       // private static CancellationTokenSource tokenSource;

        static void Main(string[] args)
        {


            var repository = new PersonRepository();
            Task<List<Person>> peopleTask = repository.GetAsync();

            peopleTask.ContinueWith(task =>
                {
                    List<Person> people = task.Result;
                    foreach(var person in people)
                        Console.WriteLine(person.ToString());
                    Environment.Exit(0);
                },
                TaskContinuationOptions.OnlyOnRanToCompletion);



        }


    }
}

====================================================================== Updated:

static void Main(string[] args)
        {
            var repository = new PersonRepository();
            Task<List<Person>> peopleTask = repository.GetAsync();
            Task<List<Person>> peopleTask1 = repository.GetAsync();
            List<Person> people = peopleTask.Result;  // or 'await' in an async Main(),  C# 7.1
            List<Person> people1 = peopleTask1.Result;  // or 'await' in an async Main(),  C# 7.1

            //Add both model to create a single
            foreach (var person in people)
                Console.WriteLine(person.ToString());
            Console.ReadLine();
        }
1

There are 1 answers

2
Henk Holterman On BEST ANSWER

Replace your Main with

var repository = new PersonRepository();
Task<List<Person>> peopleTask = repository.GetAsync();
List<Person> people = task.Result;  // or 'await' in an async Main(),  C# 7.1
foreach(var person in people)
   Console.WriteLine(person.ToString());
Console.ReadLine();

And maybe wrap it in a try/catch.
The whole ContinueWith is of no use here.

======

Edit, for multiple tasks. As I said a ConsoleApp is not great so fix that first. Makes the rest more suitable for other types of programs:

static void Main()
{
   MainAsync().Wait();  // add some error handling
}

// option 1, async and sequential
static Task MainAsync()
{
    var repository = new PersonRepository();
    List<Person> people1 = await repository.GetAsync();
    List<Person> people2 = await repository.GetAsync();
    // use the results
}

// option 2, parallel
static Task MainAsync()
{
    var repository = new PersonRepository();

   Task<List<Person>> peopleTask1 = repository.GetAsync();
   Task<List<Person>> peopleTask2 = repository.GetAsync();
   await Task.WaitAll(peopleTask1 , peopleTask2);

   List<Person> people1 = peopleTask1.Result;  // should be completed now
   List<Person> people2 = peopleTask2.Result;  

   // use the results

}

Option 2 is better for a small number of CPU intensive tasks. For calling 2 APIs at the same time probaly better too, depending on network.

Option 1 is essential when Tasks depends on each other.