SignalR OnDisconnected-신뢰할 수 있는 방법을 처리하"사용자가 온라인에 대해"채팅?

StackOverflow https://stackoverflow.com//questions/21066657

문제

나는 구간 동안 회원정보를 보관합니다.지금까지,이렇게 좋은 사용자 메시지를 보낼 수 있습에서 자신의 브라우저를 통해 JS 클라이언트가 사용하는 C#클라이언트가 같은 일-이러한 메시지를 방송을 얻을 다른 사용자.지금,나를 구현하기 위해 노력하고는"온라인 사용자".

내 방법은 다음과 같다:

  • OnConnected -업데이트 사용자에 db 하 IsOnline=true
  • OnDisconnected -는 경우에는 사용자가 어떤 다른 연결을 업데이트 사용자에 db 할 IsOnline = false
  • 나는 저장하는 상태에서 DB 기 때문에 나는 쿼리를 db 사용자를 위해 미리 어쨌든 이처럼 보였다 간단한 대체하는 작업을 사전에서는 허브입니다.

는 문제가 발생하는 OnDisconnected 지 않는 항상 호출되는 모든 클라이언트의 Id-부실 연결지 못하고 있는"는 경우에는 사용자가 어떤 다른 연결을"비트에서 확인하는 진정한 사용자는 항상"온라인".

한 해키는 방법을 지속적으로 연구할 수 있습을 생각하는 것입 설정 사용자가 오프라인에서 db 시 OnDisconnect -하지만 이것이 의미하는 경우에는 사용자가 열리는 두 개의 탭을 닫 중 하나,그들은"오프라인".이때는 다시 설정하거나 온라인 사용자는 모든 메시지가 전송되지만,이처럼 보인 총 폐기물의 처리 주기하고 여전히 양의 시간을 사용자가 본 것 같은 오프라인을 때,그들은 정말 온라인.

내가 믿는 경우 방법이 없었다는 것을 보장하는 OnDisconnected 라에 대한 모든 클라이언트,이 문제는 것입니다.그 좋아하는 경우에는 클라이언트 장(>10 분)과 그 연결 끊기 OnDisconnected 지 않 라고 합니다.I'll try my best 을 정확하게 재현 단계이 계속 업데이트됩니다.

그는 이 유효한 접근 방식을 취급하는 온라인 상태?그렇다면,다른 무엇을 할 수 있는지 확인 OnDisconnected 은 발사를 위해 모든 연결을 결?

이 문제는 걱정 때문에 기존의 연결이 성장을 계속 시간에,내가 틀리지 않는 경우,결국은 범람으로 인해 처리되지 않은 상태 연결이 있습니다.

코드:

내가 사용하는 메모리 접근 방식을 그룹화입니다.

메시지를 보내(C#):

private readonly static ConnectionMapping<string> _chatConnections =
            new ConnectionMapping<string>();
public void SendChatMessage(string key, ChatMessageViewModel message) {
            message.HtmlContent = _compiler.Transform(message.HtmlContent);
            foreach (var connectionId in _chatConnections.GetConnections(key)) {
                Clients.Client(connectionId).addChatMessage(JsonConvert.SerializeObject(message).SanitizeData());
            }
        }

주 관:

    public override Task OnConnected() {
        HandleConnection();
        return base.OnConnected();
    }

    public override Task OnDisconnected() {
        HandleConnection(true);
        return base.OnDisconnected();
    }

    public override Task OnReconnected() {
        HandleConnection();
        return base.OnReconnected();
    }

    private void HandleConnection(bool shouldDisconnect = false) {
        if (Context.User == null) return;
        var username = Context.User.Identity.Name;
        var _userService = new UserService();
        var key = username;

        if (shouldDisconnect) {
                _chatConnections.Remove(key, Context.ConnectionId);
                var existingConnections = _chatConnections.GetConnections(key);
                // this is the problem - existingConnections occasionally gets to a point where there's always a connection - as if the OnDisconnected() never got called for that client
                if (!existingConnections.Any()) { // THIS is the issue - existingConnections sometimes contains connections despite there being no open tabs/clients
                    // save status serverside
                    var onlineUserDto = _userService.SetChatStatus(username, false);
                    SendOnlineUserUpdate(_baseUrl, onlineUserDto, false);
                }
        } else {
                if (!_chatConnections.GetConnections(key).Contains(Context.ConnectionId)) {
                    _chatConnections.Add(key, Context.ConnectionId);
                }
                var onlineUserDto = _userService.SetChatStatus(Context.User.Identity.Name, true);
                SendOnlineUserUpdate(_baseUrl, onlineUserDto, true);
                // broadcast to clients
        }
    }

ConnectionMapping:

public class ConnectionMapping<T> {
        private readonly Dictionary<T, HashSet<string>> _connections =
            new Dictionary<T, HashSet<string>>();

        public int Count {
            get {
                return _connections.Count;
            }
        }

        public void Add(T key, string connectionId) {
            lock (_connections) {
                HashSet<string> connections;
                if (!_connections.TryGetValue(key, out connections)) {
                    connections = new HashSet<string>();
                    _connections.Add(key, connections);
                }

                lock (connections) {
                    connections.Add(connectionId);
                }
            }
        }

        public IEnumerable<string> GetConnections(T key) {
            HashSet<string> connections;
            if (_connections.TryGetValue(key, out connections)) {
                return connections.ToList();
            }
            return Enumerable.Empty<string>();
        }

        public void Remove(T key, string connectionId) {
            lock (_connections) {
                HashSet<string> connections;
                if (!_connections.TryGetValue(key, out connections)) {
                    return;
                }

                lock (connections) {
                    connections.Remove(connectionId);

                    if (connections.Count == 0) {
                        _connections.Remove(key);
                    }
                }
            }
        }
    }

업데이트

당 dfowler 의 제안을 대체 접근법을 것을 구현에 db 매핑을 대신에,이 방법이 이상의 메타데이터를 식별하는 데 사용될 수 있습 좀비가 연결이 있습니다.I'm hoping 에 대한 해결책을 메모리에서 문제이지만,대신 다시 건축가리 권장하는 방법 이미 구현했습니다.

도움이 되었습니까?

해결책

하려고 다음과 같은 이 샘플에 여기:

https://github.com/DamianEdwards/NDCLondon2013/tree/master/UserPresence

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top