我需要创建一个连接到第三方SOAP API的REST API。第三方API事件通过回调发送到我提供的URL。
我的API通过的典型步骤是通过提供ID和回调URL来与第三方进行会话。现在,例如当有新参与者连接时,第三方可以通过此URL将新事件发送到我的API。现在有时我需要请求特定信息,例如给定session(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方式”(出于国家考虑)。
在这里(您需要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";
}
}
另一种方式是字典主题,每节课一个,因此我可以管理它们的寿命。
答案 0 :(得分:0)
这不是一个受试者的一生
发生错误时会发生什么?
我不认为我是通过“ RX方式”完成的
是的,这些都是使用这种方法的完全有效的关注点。就个人而言,我不太在乎最后一个,因为即使主题被皱眉了,很多时候它们也比正确的Rx方法更容易使用。借助Rx的学习曲线,我倾向于针对开发人员的可维护性进行优化,因此我会“作弊”并使用Subjects,除非同样可以理解该替代方案。
关于生存期和错误,那里的解决方案取决于您希望应用程序如何运行。
在整个生命周期中,看起来您当前拥有一个WebAPI资源(SOAP连接),需要从客户端显式断开连接;这引起了一些危险信号。至少,您希望在那里存在某种超时,即使从未调用endSession
,该资源也会在那里处置。否则,最终很容易陷入资源悬空的情况。
对于错误,您还需要确定适当的方法。您可以“缓存”错误并将其报告给每个尝试使用该资源的调用,并在调用endSession
时“清除”错误。或者,如果更合适,则可以让错误减少您的ASP.NET进程。 (ASP.NET将为您重新启动一个新版本。)
要延迟API直到发生其他事件,请使用TaskCompletionSource<T>
。启动SOAP调用(例如ExternAPI.participants
)时,您应该创建一个新的TCS<T>
。然后,API调用应await
TaskCompletionSource<T>.Task
。当SOAP服务响应事件时,它应该使用TaskCompletionSource<T>
并完成它。注意事项:
TaskCompletionSource<T>
实例的 collection 以及某种消息标识符来进行匹配哪些事件适合哪些电话。TaskCompletionSource<T>
本身是线程安全的,但是您还需要使集合的线程安全。您可能想先为SOAP服务编写一个基于Task
的包装器(处理所有TaskCompletionSource<T>
东西),然后从WebAPI中使用那个。 / p>
作为一个非常广泛的替代方案,我将考虑使用SignalR桥接SOAP,而不是使用WebAPI桥接SOAP。您可能会发现这是更自然的翻译。除其他外,SignalR将为您提供客户端连接和客户端断开事件(客户端内置的超时功能)。这样可以更自然地解决您的一生问题。您也可以对您的SOAP服务使用相同的基于Task
的包装器,也可以直接将SOAP事件作为SignalR消息公开。