Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect that a client closed the browser on Blazor server side (web socket connection closed)?

I am trying to detect when a client disconnects from a Blazor server side app; this would probably be equal to the web socket connection being closed. Can you suggest a way to detect such an event on the server side?

like image 903
aleksander_si Avatar asked Oct 02 '19 10:10

aleksander_si


1 Answers

I have examined the ASP.NET Core 3.1 functionality and tested that it is indeed possible to detect an event when a user navigates away from a component or when the browser is closed.

To detect when a user navigates away from a component or when a component is disposed of, but not discerning if this was due to clicking a link in an application or simply because of navigating to a different URL or by closing the browser window:

AddressBase.razor.cs:

public class AddressBase : ComponentBase, IDisposable
{
        void IDisposable.Dispose()
        {
            Console.WriteLine("Disposing AddressBase.");
        }
}

Address.razor:

@page "/address"
@inherits AddressBase

<h1>Address component</h1>

The Dispose() function will be triggered for all components currently displayed on a page when browser window is closed or when user navigates to a different view in the application or different URL entirely.

To detect that a user has actually left the application:

Blazor uses Blazor circuits for maintaining information about user and scoped services. Circuits have lifetime events and it is possible to register event handlers for them. To do that, extend the CircuitHandler class and register it using DI. CircuitHandler will handle the following events:

  • OnCircuitOpenedAsync
  • OnConnectionUpAsync
  • OnConnectionDownAsync
  • OnCircuitClosedAsync

It also defines the Order property which can be used for execution ordering of multiple CircuitHandlers.

using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.Server.Circuits;

public class TrackingCircuitHandler : CircuitHandler
{
    private HashSet<Circuit> circuits = new HashSet<Circuit>();

    public override Task OnConnectionUpAsync(Circuit circuit, 
        CancellationToken cancellationToken)
    {
        circuits.Add(circuit);

        return Task.CompletedTask;
    }

    public override Task OnConnectionDownAsync(Circuit circuit, 
        CancellationToken cancellationToken)
    {
        circuits.Remove(circuit);

        return Task.CompletedTask;
    }

    public int ConnectedCircuits => circuits.Count;
}

// ...

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddSingleton<CircuitHandler, TrackingCircuitHandler>();
}

https://docs.microsoft.com/en-us/aspnet/core/blazor/advanced-scenarios?view=aspnetcore-3.1 https://source.dot.net/#Microsoft.AspNetCore.Components.Server/Circuits/CircuitHandler.cs

like image 166
aleksander_si Avatar answered Sep 17 '22 20:09

aleksander_si