我是.NET Core
和异步编程的新手。我正在尝试实现一个控制台应用程序来执行以下操作:
控制台应用程序应该作为两个外部API之间的中介。例如。 API-1和API-2。
它应该在每10毫秒后调用API-1来获取数据。
立即调用API-2提交从API-1收到的数据。
以下是我的代码。它没有按预期工作。首先,它按预期在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);
}
}
}
POCO课程
namespace ConsoleApp1
{
public class SomeData
{
public string SomeStringValue { get; set; }
}
}
另请注意,API-1和API-2将在ASP.NET Core 1
中开发 UPDATE1
让我重新说一句。 API-1将在.Net核心中开发,但API-2将是Windows工作流服务。这意味着我们可以多次调用WF。 WF将持续保留请求并一次处理一个。
UPDATE2
完成所有答案和提供的链接后。我想使用Windows服务作为中介而不是控制台应用程序。现在.Net core
不支持窗口服务,但是这个nuget-package可以在Windows服务中托管.Net核心,或者我可以使用4.6.2的经典Windows服务。我想我也可以在Windows服务中做异常的实现。
答案 0 :(得分:2)
在这种情况下,我会做很多不同的事情。我也不会使用计时器,而是使用Task.Delay
,在尝试向其投入更多数据之前,我肯定会等待API2完成。此外,我会确保我的async
方法返回Task
或Task<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);
}
}
这将采取以下方式:
最后,无论您是否使用.NET Core
,这都是相同的建议。任何API交互都应遵循相同的准则。
备注强>
在第二次API调用中使用“即发即忘”只是将代码设置为失败。由于它是一个API调用,因此I/O
绑定操作可能会出现一些延迟,并且应该假设10毫秒的紧密循环只会泛滥该端点上的可用性。为什么不等到它完成,你可能有什么理由?
答案 1 :(得分:0)
调用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);
}
修改:
大卫指出,当然有很多方法可以解决这个问题。这不是解决问题的正确方法。
另一种做法是使用quartz.net
这样,当API2失败时,您可以重播/重复该作业。