首页 > 解决方案 > 检测用户何时离开(即关闭浏览器)

问题描述

我有一个 Singleton 服务,GameServer它跟踪访客到特定页面、Game.razor页面和 Scoped 服务,GameBridge它们之间。 Gamebridge被注入Game.razor,GameServer被注入Gamebridge.

GameServer发出一个 ping 事件,该事件由GameBridge该页面中继。然后页面调用 中的方法Gamebridge,该方法被中继到GameServer,并LastSeen为用户将 DateTime 设置为 DateTime.Now。

这个想法是,如果用户关闭他们的浏览器,Scoped 服务将被GameServer释放,并且将不再从用户那里获得更新 ping,即用户已超时,游戏可能会被没收,游戏室被放弃等等。

问题是,即使浏览器已关闭,Game.razor并且GameBridge继续运行,一切都很好——我可以看到,因为丢失用户的时间值不断更新。截至目前,即使用户在 blazor 服务器端关闭浏览器,我也无法检测到用户断开连接。

标签: c#blazorblazor-server-side

解决方案


我的解决方案与浏览器窗口beforeunload事件挂钩,并使用 Guid 来跟踪 SPA 会话。

这是我的演示系统,您可以根据自己的代码进行调整。

添加一个单例服务并注册它。

using System;

namespace Blazor.App.Services
{
    public class SessionTrackerService
    {
        // Session List, blah, blah, ..

        public void NotifyNewSession(Guid ID)
        {
            //  Do whatever you want
            Debug.WriteLine($"Session {ID} Registered");
        }

        public void NotifySessionClosed(Guid ID)
        {
            var x = 0;
            Debug.WriteLine($"Session {ID} Closed");
            // Do re-registering
        }
    }
}

site.js在基本页面中注册。

window.blazor_setExitEvent = function (dotNetHelper) {
    blazor_dotNetHelper = dotNetHelper;
        window.addEventListener("beforeunload", blazor_SetSPAClosed);
}

var blazor_dotNetHelper;

window.blazor_SetSPAClosed = function() {
    blazor_dotNetHelper.invokeMethodAsync('SPASessionClosed')
    blazor_dotNetHelper.dispose();
}

添加一些代码到App.razor. SessionID如果您需要在其他地方使用它,请级联。调用window.blazor_setExitEvent以设置窗口beforeunload事件并将其传递给App.

<CascadingValue Name="SessionID" Value="this.ID">
    <Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true">
        .....
    </Router>
</CascadingValue>

@code {
    [Inject] private IJSRuntime _js { get; set; }
    [Inject] private SessionTrackerService sessionTrackerService { get; set; }
    public Guid ID { get; set; } = Guid.NewGuid();

    protected async override Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            sessionTrackerService.NotifyNewSession(ID);
            var dotNetReference = DotNetObjectReference.Create(this);
            await _js.InvokeVoidAsync("window.blazor_setExitEvent", dotNetReference);
        }
    }

    [JSInvokable("SPASessionClosed")]
    public void SPASessionClosed()
    {
        sessionTrackerService.NotifySessionClosed(ID);
    }

我在 Edge、Chrome 和 Firefox 上进行了测试。


推荐阅读