信号器 - 可以等待来自客户的响应吗?

时间:2018-01-16 19:12:16

标签: c# signalr

我是使用Signalr的初学者,正在查看一些例子。

是否可以从服务器向客户端发送消息并等待从中返回?或者是否可以保证在答案之后会使用相同的会话?

我的问题是因为在给定的流程中,在一个事务中,我需要询问用户是否要继续进行更改。我以前无法提出这个问题,因为验证应该在已进行更改的同一会话中完成(但尚未确认)。

3 个答案:

答案 0 :(得分:6)

重申Jaime Yule的评论,WebSockets是双向通信,不遵循请求/响应架构进行消息传递。鉴于围绕WebSockets的通信非常流畅,这些要点对于您当前(和未来)的场景都要记住:

  • 如果您要将它用于火灾,那么SignalR非常棒忘记(向用户显示弹出窗口,以及<)。
  • 它并非围绕请求 - 响应而设计,就像您要求的那样,并尝试使用它是一种反模式
  • 可以随时从连接的任一端发送消息, 并且没有本地支持一条消息来表明它是 与另一个相关的
  • 这使得协议不适合交易要求

答案 1 :(得分:1)

在Invoke中使用以下形式等待并直接返回响应(就像“真正的”同步方法调用一样)

        var persons = hubProxy.Invoke<IEnumerable<Person>>("GetPersonsSynchronous", SearchCriteria, noteFields).Result;

        foreach (Person person in persons)
        {
            Console.WriteLine($"{person.LastName}, {person.FirstName}");
        }

答案 2 :(得分:1)

有可能,但我不建议(依靠)它。
而且这不是一个很好的解决方案(使用静态事件,并且对于如此简单的事情非常复杂)。

故事是这样的:

确保客户端和服务器知道connectionId-他们可能已经知道了,但是我想不出一种方法来访问它。

等待NotificationService.ConfirmAsync
...将在客户端上调用confirm
...将等待用户提供的答案
...并使用集线器中的Callback将其发送回服务器。
...,它将通过静态事件从NotificationService通知回调
...会将message切换回ConfirmAsync(使用AutoResetEvent
...希望仍在等待中:)

客户端和服务器都设置了10秒的超时时间。

中心:

    // Setup as /notification-hub
    public class NotificationHub : Hub {
        public string ConnectionId() => Context.ConnectionId;
        public static event Action<string, string> Response;
        public void Callback(string connectionId, string message) {
            Response?.Invoke(connectionId, message);
        }
    }

服务:

    // Wire it up using DI
    public class NotificationService {
        private readonly IHubContext<NotificationHub> _notificationHubContext;
        public NotificationService(IHubContext<NotificationHub> notificationHubContext) {
            _notificationHubContext = notificationHubContext;
        }

        public async Task<string> ConfirmAsync(string connectionId, string text, IEnumerable<string> choices) {
            await _notificationHubContext.Clients.Client(connectionId)
                                         .SendAsync("confirm", text, choices);
            var are = new AutoResetEvent(false);
            string response = null;
            void Callback(string connId, string message) {
                if (connectionId == connId) {
                    response = message;
                    are.Set();
                }
            }
            NotificationHub.Response += Callback;
            are.WaitOne(TimeSpan.FromSeconds(10));
            NotificationHub.Response -= Callback;
            return response;
        }
    }

客户端js:

    var conn = new signalR.HubConnectionBuilder().withUrl("/notification-hub").build();
    var connId;

    // using Noty v3 (https://ned.im/noty/)
    function confirm(text, choices) {
        return new Promise(function (resolve, reject) {
            var n = new Noty({
                text: text,
                timeout: 10000,
                buttons: choices.map(function (b) {
                    return Noty.button(b, 'btn', function () {
                        resolve(b);
                        n.close();
                    });
                })
            });
            n.show();
        });
    }

    conn.on('confirm', function(text, choices) {
        confirm(text, choices).then(function(choice) {
            conn.invoke("Callback", connId, choice);
        });
    });

    conn.start().then(function() {
        conn.invoke("ConnectionId").then(function (connectionId) {
            connId = connectionId;
            // Picked up by a form and posted to the server
            document.querySelector(".connection-id-input").value = connectionId;
        });
    });

对我来说,这是将其放入我正在研究的项目中的复杂方法。
看起来好像真的会回来,以后再咬你...