是否有SignalR替代品具有“向服务器返回值”功能?

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

我的目标:传递数据给连接到服务器特定客户端,并获得结果,而无需调用服务器方法。

我尝试使用SignalR来执行此操作(因为这对我来说是非常简单的工具),但是我无法获得结果(现在我知道为什么)。我正在使用ASP.NET Core 3.1。

我的问题:是否存在具有“向服务器返回值”功能的SignalR替代方案(在目标客户端上调用带有参数的方法并获得结果)?

c# asp.net-core signalr ipc rpc
1个回答
1
投票

SignalR通常用于存在多个客户端和一个客户端连接到单个服务器的设置中。这使客户端调用服务器并期待返回结果成为正常的事情。由于服务器通常并不真正关心连接的是什么[单个]客户端,并且由于服务器通常向一组客户端广播(例如使用一组),因此通信方向主要用于通知或广播。单目标消息是可能的,但没有用于请求/响应模式的内置机制。为了与SignalR一起使用,您

需要一种让客户端回叫服务器的方法。因此,您将需要执行中心操作来将响应发送到。仅此一项并不困难,但是可能要做的是,您需要将客户呼叫与中心收到的传入结果消息相关联。为此,您将需要构建一些东西。

这里是一个示例实现,可以帮助您入门。 MyRequestClient是一个单例服务,基本上封装了消息传递,并为您提供了一个异步方法,该方法将调用客户端,并且仅在客户端通过调用集线器上的回调方法来响应时才完成:

public class MyRequestClient { private readonly IHubContext<MyHub> _hubContext; private ConcurrentDictionary<Guid, object> _pendingTasks = new ConcurrentDictionary<Guid, object>(); public MyRequestClient(IHubContext<MyHub> hubContext) { _hubContext = hubContext; } public async Task<int> Square(string connectionId, int number) { var requestId = Guid.NewGuid(); var source = new TaskCompletionSource<int>(); _pendingTasks[requestId] = source; await _hubContext.Clients.Client(connectionId).SendAsync("Square", nameof(MyHub.SquareCallback), requestId, number); return await source.Task; } public void SquareCallback(Guid requestId, int result) { if (_pendingTasks.TryRemove(requestId, out var obj) && obj is TaskCompletionSource<int> source) source.SetResult(result); } }

然后在中心,您需要回调操作来调用请求客户端以完成任务:

public class MyHub : Hub { private readonly ILogger<MyHub> _logger; private readonly MyRequestClient _requestClient; public MyHub(ILogger<MyHub> logger, MyRequestClient requestClient) { _logger = logger; _requestClient = requestClient; } public Task SquareCallback(Guid requestId, int number) { _requestClient.SquareCallback(requestId, number); return Task.CompletedTask; } // just for demo purposes public Task Start() { var connectionId = Context.ConnectionId; _ = Task.Run(async () => { var number = 42; _logger.LogInformation("Starting Square: {Number}", number); var result = await _requestClient.Square(connectionId, number); _logger.LogInformation("Square returned: {Result}", result); }); return Task.CompletedTask; } }

Start集线器操作仅出于演示目的,具有使用有效的连接ID来启动它的方法。

然后,在客户端上,您需要实现client方法,并在完成后让它调用指定的回调方法:

connection.on('Square', (callbackMethod, requestId, number) => { const result = number * number; connection.invoke(callbackMethod, requestId, result); });

最后,您可以通过调用客户端的Start操作来尝试此操作:

connection.invoke('Start');

当然,这种实现是非常基本的,并且需要一些诸如正确的错误处理之类的东西,如果客户端没有正确响应,则需要支持超时任务。也可以将其扩展为支持任意调用,而无需您手动创建所有这些方法(例如,通过在集线器上使用一个能够完成任何任务的回调方法)。
© www.soinside.com 2019 - 2024. All rights reserved.