使用.net Core进行异步编程

本文关键字:异步 编程 net Core 使用 | 更新日期: 2023-09-27 18:01:57

我是.NET Core和异步编程的新手。我正试图实现一个控制台应用程序来做以下事情:

  1. 控制台应用程序应该作为两个外部api之间的中介。如。API-1和API-2.

  2. 它应该在每10毫秒之后调用API-1来获取数据。

  3. 立即调用API-2提交从API-1接收到的数据

  4. 控制台应用程序需要等待API-1接收数据,但不必等待API-2的响应。

下面是我的代码。它没有像预期的那样工作。起初,它像预期的那样在10毫秒内调用API-1,但在此之后,它只在收到API-2的响应后才调用API-1。
所以假设API-2花了20秒,API-1也会在20秒后被调用。

我如何使API-2调用异步,使它不必等待API-2响应?

namespace ConsoleApp1
{
    public class Program
    {
        private static Timer _timer;
        private const int TIME_INTERVAL_IN_MILLISECONDS = 10; // 10 milliseconds
        private const int API2_DELAY = 20000; // 20 seconds
        public static void Main(string[] args)
        {
            Dowork().Wait();
            Console.WriteLine("Press Any Key to stop");
            Console.ReadKey();
            Console.WriteLine("Done");
        }
        private static async Task Dowork()
        {
            var data = new SomeData();
            _timer = new Timer(CallAPI1, data, TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite);
            await Task.Yield();            
        }
        private static async void CallAPI1(object state)
        {           
            var data = state as SomeData;
            Console.WriteLine("Calling API One to get some data.");
            data.SomeStringValue = DateTime.Now.ToString();
            await CallAPI2(data);
            _timer.Change(TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite);
        }
        private static async Task CallAPI2(SomeData data)
        {           
            Console.WriteLine("Calling API Two by passing some data received from API One " + data.SomeStringValue);
            // the delay represent long running call to API 2
            await Task.Delay(API2_DELAY);
        }
    }
}

少类

namespace ConsoleApp1
{
    public class SomeData
    {
        public string SomeStringValue { get; set; }
    }
}

还要注意API-1和API-2将在ASP中开发。Core 1

Update1
让我把上面的句子改写一下。API-1将在。net核心中开发,而API-2将是windows工作流服务。这意味着我们可以给WF打多个电话。WF将保存请求并一次处理一个。

更新2
在浏览了所有提供的答案和链接之后。我正在考虑使用windows服务作为中介,而不是控制台应用程序。现在.Net core不支持窗口服务,但有这个nuget-package,可以在windows服务中托管。net核心,或者我可能使用使用4.6.2的经典windows服务。我想我也可以在windows服务中实现异步。

使用.net Core进行异步编程

在这种情况下,我有很多不同的做法。而不是使用定时器,我会使用Task.Delay,也-我肯定会等待API2完成之前,试图扔更多的数据在它。此外,我会确保我的async方法是TaskTask<T>返回,注意你的CallAPI1调用不是,我理解它是一个计时器回调-但这是另一个问题。

考虑以下内容:

async Task IntermediateAsync()
{
    Console.WriteLine("Press ESC to exit...");
    while (Console.ReadKey(true).Key != ConsoleKey.Escape)
    {
        var result = await _apiServiceOne.GetAsync();
        await _apiServiceTwo.PostAsync(result);
        // Wait ten milliseconds after each successful mediation phase
        await Task.Delay(10);
    }
}

这将以以下方式起作用:

  1. 打印一行指示用户如何退出
  2. 开始循环
  3. 获取API1的结果
  4. 将结果传递给API2
  5. 等待10毫秒(步骤2)

最后,无论您是否使用.NET Core,这都是相同的建议。任何API交互都应该遵循相同的指导原则。

指出

在第二个API调用中使用"即发即弃"方法只会导致代码失败。由于这是一个API调用,因此I/O绑定操作很可能会有一些延迟,并且应该假设10毫秒的紧密循环只会淹没该端点上的可用性。为什么不干脆等它做完呢,你有什么理由呢?

删除调用API2时的await

    private static async void CallAPI1(object state)
    {
        var data = state as SomeData;
        Console.WriteLine("Calling API One to get some data.");
        data.SomeStringValue = DateTime.Now.ToString();
        //Before this will cause the program to wait
        await CallAPI2(data);
        // Now it will call and forget
        CallAPI2(data);
        _timer.Change(TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite);
    }
编辑:

正如David指出的,当然有很多方法可以解决这个问题。这不是解决问题的正确方法。

另一种方法是使用quartz.net

  1. 将API1调度为重复作业
  2. 当API1完成时,调度另一个作业将API2作为独立作业运行

这样,当API2失败时,您可以重放/重复作业。