等待第三方API回调

问题描述 投票:0回答:1

我需要创建一个连接到第三方SOAP API的REST API。第三方API事件通过回调发送到我提供的URL。

我的API经历的典型步骤是通过提供ID和回调URL来启动与第三方的会话。第三方现在可以通过此URL向我的API发送新事件,例如,当新参与者连接时。现在有时我需要请求特定信息,例如给定会话(ID)的参与者列表,并等待包含信息的事件。请注意,可能同时有多个打开的会话。

我需要的一个例子:

private string url = "http://myapi/callback";

[HttpGet]
[Route("createSession")]
public async Task<string> CreateSession()
{
    var id = Guid.NewGuid().ToString();
    var result = await ExternAPI.CreateSession(id, this.url);
    return result; //contains the id
}

[HttpGet]
[Route("endSession")]
public async Task<string> EndSession([FromUri] string id)
{
    var result = await ExternAPI.EndSession(id);
    return result;
}

[HttpGet]
[Route("partipants")]
public async Task<string> Partipants([FromUri] string id)
{
    ExternAPI.participants(id); // The results of this method will be sent to the callback function
    results = // Wait for the results for this id
    return results;
}

[HttpPost]
[Route("callback")]
public void Callback(body)
{
    // notify waiting function and pass body
}

我想出了一个使用ReactiveX的解决方案,但我不确定它在生产中的可靠性。我想到的是创建一个永远不会终止和处理所有事件的主题,但它不是主题的通常生命周期,错误会发生什么?我不认为我是“RX-way”(国家担忧)。

这是(您将需要System.Reactive来运行此代码):

class Data
{
    public int id;
    public string value;
}

class Program
{
    private static Subject<Data> sub;

    static void Main(string[] args)
    {
        sub = new Subject<Data>();
        Task.Run(async () => {
            int id = 1;
            ExternAPI(CallBackHook, id);
            Data result = await sub.Where(data => data.id == id).FirstAsync();
            Console.WriteLine("{0}", result.value);
        });
        Console.ReadLine();
    }

    static void CallBackHook(Data data)
    {
        sub.OnNext(data);
    }

    static String ExternAPI(Action<Data> callback, int id)
    {
        // Third-party API, access via SOAP. callback is normally an url (string)
        Task.Run(() =>
        {
            Thread.Sleep(1000);
            callback(new Data { id = id, value = "test" });
        });
        return "success";
    }
}

另一种方式是主题词典,每个会话一个,所以我可以管理他们的一生。

c# .net asp.net-web-api2 reactive-programming system.reactive
1个回答
0
投票

这不是一个主题的通常生命

错误会发生什么?

我不认为我是“RX-way”

是的,这些都是这种方法的完全有效的关注点。就个人而言,我并不介意最后一个,因为即使主题是皱眉,很多时候它们比正确的Rx方式更容易使用。随着Rx的学习曲线是什么,我倾向于优化开发人员的可维护性,所以我做“欺骗”并使用主题,除非替代方案同样可以理解。

关于生命周期和错误,那里的解决方案取决于您希望应用程序的行为方式。

对于生命周期,看起来目前您有一个WebAPI资源(SOAP连接)需要来自客户端的显式断开连接调用;这引起了一些危险信号。至少,你需要某种超时,即使从未调用过endSession,该资源也会被处理掉。否则,结束悬空资源将太容易了。

另外,对于错误,您需要确定适当的方法。您可以“缓存”错误并将其报告给尝试使用该资源的每个调用,并在调用endSession时“清除”错误。或者,如果它更合适,您可以让错误消除您的ASP.NET进程。 (ASP.NET将为您重新启动一个新的)。

要延迟API直到您获得其他事件,请使用TaskCompletionSource<T>。在启动SOAP调用(例如,ExternAPI.participants)时,您应该创建一个新的TCS<T>。然后API调用await TaskCompletionSource<T>.Task。当SOAP服务响应事件时,应该使用TaskCompletionSource<T>并完成它。注意事项:

  • 如果有多个SOAP调用期望对同一事件做出响应,则需要一组TaskCompletionSource<T>实例,以及某种消息标识符,以匹配哪些事件用于哪些调用。
  • 一定要注意你的线程安全。传入的SOAP事件很可能到达线程池,其他线程池线程上有(可能是多个)API请求。 TaskCompletionSource<T>本身就是线程安全的,但你也需要让你的集合线程安全。

您可能希望首先为SOAP服务编写基于Task的包装器(处理所有TaskCompletionSource<T>的东西),然后从WebAPI中使用它。

作为一个非常广泛的替代方案,我不会考虑使用WebAPI桥接SOAP,而是考虑使用SignalR桥接SOAP。您可能会发现这是一种更自然的翻译。除此之外,SignalR还将为您提供客户端连接和客户端断开事件(完成客户端的内置超时)。这样可以更自然地解决您的终身问题。您也可以为SOAP服务使用相同的基于Task的包装器,或者直接将SOAP事件作为SignalR消息公开。

© www.soinside.com 2019 - 2024. All rights reserved.