dsuryd / dotNetify

Simple, lightweight, yet powerful way to build real-time web apps.
https://dotnetify.net
Other
1.17k stars 164 forks source link

What's a good way to detect that a caller has disconnected from a ViewModel? #151

Closed bugged84 closed 5 years ago

bugged84 commented 5 years ago

I'm trying to detect when users connect and disconnect from my VM. Detecting the connection is easy using the OnRouted handler.

this.OnRouted((sender, e) =>
{
    var userId = hubCallerContextAccessor.CallerContext.ConnectionId;

    // handle user entry
    m_users.Add(userId);

    // subscribe to user exit
    m_hubCallerContextAccessor.CallerContext.ConnectionAborted.Register(() =>
    {
        m_users.Remove(userId); // never gets called...
    }    
});

However, I'm not able to come up with a reliable way to know on the server when a user disconnects.

Do I have to resort to adding a KeepAlive action on the VM that the React component calls on regular intervals, and then the VM removes any user that has not reported in recently?

dsuryd commented 5 years ago

Like in the chat room example, make an explicit dispatch from componentWillUnmount to let the VM knows the user is leaving. Also for non websocket connection, handle window before unload event too.

On Fri, Nov 23, 2018 at 11:25 AM bugged84 notifications@github.com wrote:

I'm trying to detect when users connect and disconnect from my VM. Detecting the connection is easy using the OnRouted handler.

this.OnRouted((sender, e) => { var userId = hubCallerContextAccessor.CallerContext.ConnectionId;

// handle user entry
m_users.Add(userId);

// subscribe to user exit
m_hubCallerContextAccessor.CallerContext.ConnectionAborted.Register(() =>
{
    m_users.Remove(userId); // never gets called...
}

});

However, I'm not able to come up with a reliable way to know on the server when a user disconnects.

Do I have to resort to adding a KeepAlive action on the VM that the React component calls on regular intervals, and then the VM removes any user that has not reported in recently?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/dsuryd/dotNetify/issues/151, or mute the thread https://github.com/notifications/unsubscribe-auth/AOS8ktDEBMbijJ_qmV3Y59rugxV83eKxks5uyEuSgaJpZM4YxDoL .

bugged84 commented 5 years ago

That was one of the options I considered. However, that would not be purely server side detection. For example, what if the user's device suddenly crashes or loses internet? I want the server to be able to detect this and boot the user from the chat room. Depending on a react component for this detection will introduce an unstable chat room. This problem only becomes worse if, for example, you're dealing with a game that has active players.

A keep-alive approach is the only one I could think of that would handle my scenario above. If a user suddenly stops calling in, the server would be able to notice and boot the user without an explicit call from the user to do so.

Thoughts on that?

dsuryd commented 5 years ago

I don’t have it off the top of my head, but there could be an event that SignalR provides for such scenario. Check their doc, then we’ll figure out how to access it from the VM.

bugged84 commented 5 years ago

SignalR hubs have the following lifecycle methods that can overridden.

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

public override Task OnDisconnected()
{
    //custom logic here
    return base.OnDisconnected();
}

public override Task OnReconnected()
{
    return base.OnReconnected();
}
dsuryd commented 5 years ago

You can use IDisconnectionMiddleware to hook to that OnDisconnected method.

On Fri, Nov 23, 2018 at 1:09 PM bugged84 notifications@github.com wrote:

SignalR hubs have the following lifecycle methods that can overridden.

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

public override Task OnDisconnected() { //custom logic here return base.OnDisconnected(); }

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

— You are receiving this because you commented.

Reply to this email directly, view it on GitHub https://github.com/dsuryd/dotNetify/issues/151#issuecomment-441318058, or mute the thread https://github.com/notifications/unsubscribe-auth/AOS8kqGn1utz_fKxK-cTB0s5saItfcYZks5uyGPugaJpZM4YxDoL .

bugged84 commented 5 years ago

Also, apparently the MulticastVm.Dispose() method is called each time one of these sudden disconnections happen. I moved my "remove" logic to the Dispose method and it seems to be working as expected.

dsuryd commented 5 years ago

Yes, of course, that what I should have mentioned to you from the beginning :). Need to put this in the doc.