I'm using a singleton service in a Blazor Server app to notify components when an order changes. The service follows an observer pattern, where pages register event handlers that get triggered when an update occurs.
public class OrderOnChangeService : IOrderOnChangeService{ public event Action<List<int>, Guid>? OnOrderRowChanged; public void NotifyOrderRowChanged(List<int> orderIds, Guid changeId) { OnOrderRowChanged?.Invoke(orderIds, changeId); } public int GetObserverCount() { return OnOrderRowChanged?.GetInvocationList().Length ?? 0; }}In my Blazor component (.razor.cs), I register a method with this service:
protected override async Task OnInitializedAsync(){ OrderOnChangeService.OnOrderRowChanged += HandleRowChanged; Console.WriteLine($"Registered: {OrderOnChangeService.GetObserverCount()} observers");}public void Dispose(){ OrderOnChangeService.OnOrderRowChanged -= HandleRowChanged; Console.WriteLine($"Disposed: {OrderOnChangeService.GetObserverCount()} observers");}private void HandleRowChanged(List<int> orderIds, Guid changeId){ // Handle updates}When I refresh the page, the Blazor circuit is terminated, but since OrderOnChangeService is a singleton, it still holds references to handlers from the disposed page instance. This seems to cause a memory leak because the event references are never removed unless the Dispose method is explicitly called.
How can I ensure that event handlers are always removed when a Blazor page is refreshed, so that the singleton service doesn’t keep stale references?