SignalR - правильная реализация чата

Мне нужно реализовать чат на моем веб-проекте. Как реализовать это на одной странице - об этом много статей. Но мне нужно иметь возможность: 1. Уведомить других пользователей, что кто-то вошел на сайт (на любой странице, не только на странице чата) 2. Уведомить других пользователей, что кто-то вышел из системы

Итак, у меня есть следующий код хаба:

    public void Connect()
    {
        try
        {
            var id = Context.ConnectionId;
            string username = Context.User.Identity.Name;

            var currentUser = connectedUsers.Where(p => p.Username == username).FirstOrDefault();
            if (currentUser == null)
            {
                AddNewUserToCollection();
            }
            else
            {
                // update ConnectionId for sure (connection id is changed sometimes (probably if user is logged out and login again))
                if (currentUser.ConnectionId != id)
                {
                    var companyId = _chatRepository.GetCompanyIdOfUser(username); // throws exception if companyId is null
                    Groups.Remove(currentUser.ConnectionId, companyId.ToString());
                    Groups.Add(id, companyId.ToString());
                    currentUser.ConnectionId = id;
                    //Clients.Group(companyId.ToString()).onNewUserConnected(username);
                }
            }
        }
        catch(InvalidCompanyException c_ex)
        {
            Clients.Client(Context.ConnectionId).onErrorMessage($"User '{c_ex.Username}' does not exist");
        }
    }


    public void Disconnect()
    {
        string username = Context.User.Identity.Name;
        var item = connectedUsers.Where(p => p.Username == username).FirstOrDefault();
        if (item != null)
        {
            connectedUsers.Remove(item);
            Groups.Remove(item.ConnectionId, item.CompanyID.ToString());
            Clients.Group(item.CompanyID.ToString()).onUserDisconnected(item.Username);
        }
    }

    public override Task OnDisconnected(bool stopCalled)
    {
        var item = connectedUsers.Where(p => p.ConnectionId == Context.ConnectionId).FirstOrDefault();
        if (item != null)
        {
            connectedUsers.Remove(item);
            Groups.Remove(item.ConnectionId, item.CompanyID.ToString());
            Clients.Group(item.CompanyID.ToString()).onUserDisconnected(item.Username);
        }
        return base.OnDisconnected(stopCalled);
    }

и я добавил следующий код в _layout.cshtml:

    <script>
        $(document).ready(function () {
            var chat = $.connection.chatHub;

            $.connection.hub.start().done(function () {
                chat.server.connect();
            });
        });
    </script>

уведомить других пользователей, что текущий пользователь зарегистрирован. Но отладчик говорит, что пара OnDisconnected/Connect вызывается каждый раз, когда пользователь перезагружает страницу (переходят по страницам) с другим connectionId. Когда я удаляю этот код клиента - эта пара не называется. Как правильно это реализовать, чтобы уведомить других пользователей, что кто-то в сети, но каждый раз без повторного подключения?

1 ответ

Решение

Поскольку у вас есть вызов connect() на странице бритвы (_layout.cshtml), вы будете эффективно отключаться / подключаться к каждому посту обратно (загрузка страницы).

Сценарий, который вы пытаетесь использовать, лучше всего подходит для сценария SPA (или AJAX), где навигация выполняется асинхронно с помощью клиентского JavaScript. Ваша текущая настройка обновляет экран, перезагружает JavaScript, перезапускает функцию document ready() с каждым отображаемым сервером переходом.

Другой альтернативой является использование действительного идентификатора пользователя клиента и передача его методу server.connect(id). Затем используйте этот идентификатор пользователя для отслеживания активности пользователя вместо хаба ConnectionId.

Другие вопросы по тегам