【问题标题】:Code is bypassing await and not stoppping for api to complete [duplicate]代码绕过等待而不是停止 api 完成 [重复]
【发布时间】:2018-12-05 05:24:11
【问题描述】:

参考我之前的问题,我进行了必要的更改,但我的代码仍然提供空白数据。所以,我创建了一个 poc,但这有一些问题(空白数据作为输出)。 我可以在浏览 'http://localhost:50193/api/people' 时看到 json 输出

在调试时,我发现了以下信息。

POC 错误; 状态=等待或激活。 方法="空" 结果 - 尚未计算。

另外,程序正在HttpResponseMessage response = await client.GetAsync("api/people"); 上退出,所以我无法进一步调试。

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>();
        }
    }
}

程序.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);



        }


    }
}

================================================ ======================== 更新:

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();
        }

【问题讨论】:

  • 控制台应用不是测试异步方法的最佳场所。在 Main() 的末尾放一个 ReadLine(),给任务时间来完成。
  • 我试过 readline 但它也没有返回任何东西
  • 另外,我相信我已经添加了等待,所以它应该可以处理所需的时间。我的理解是错误的应用程序

标签: c# multithreading async-await


【解决方案1】:

替换你的 Main
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();

也许将它包装在 try/catch 中。
整个 ContinueWith 在这里没有用。

======

编辑,用于多个任务。 正如我所说,ConsoleApp 不是很好,所以先解决这个问题。使其余部分更适合其他类型的程序:

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

}

选项 2 更适合少量 CPU 密集型任务。同时调用 2 个 API 也可能更好,具体取决于网络。

当任务相互依赖时,选项 1 是必不可少的。

【讨论】:

  • 非常感谢,先生,但你能解释一下吗。是什么挂了,因为它类似于我的解决方案,为什么我的不工作?另外,如果我需要 2 个任务并且想要在从两者获得结果后工作任务,我可以用我更新的答案吗
  • 更多任务,请使用WaitAll()。不确定您的 CobtnuWith 出了什么问题或目的是什么。但只要保持简单,总是会更好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-20
  • 2019-12-18
  • 1970-01-01
  • 1970-01-01
  • 2014-12-31
  • 2021-05-19
  • 2023-01-23
相关资源
最近更新 更多