我的目标:传递数据给连接到服务器的特定客户端,并获得结果,而无需调用服务器方法。
我尝试使用SignalR来执行此操作(因为这对我来说是非常简单的工具),但是我无法获得结果(现在我知道为什么)。我正在使用ASP.NET Core 3.1。
我的问题:是否存在具有“向服务器返回值”功能的SignalR替代方案(在目标客户端上调用带有参数的方法并获得结果)?
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');
当然,这种实现是非常基本的,并且需要一些诸如正确的错误处理之类的东西,如果客户端没有正确响应,则需要支持超时任务。也可以将其扩展为支持任意调用,而无需您手动创建所有这些方法(例如,通过在集线器上使用一个能够完成任何任务的回调方法)。