I've posted an answer to a question in stackoverflow C# counter to count up to a target number. Here's the answer:
You can create a timer service that can serve you on many occasions:
Create the service class:
public class BlazorTimer
{
private Timer _timer;
internal void SetTimer(double interval)
{
_timer = new Timer(interval);
_timer.Elapsed += NotifyTimerElapsed;
_timer.Enabled = true;
_timer.Start();
}
private void NotifyTimerElapsed(object sender, ElapsedEventArgs e)
{
OnElapsed?.Invoke();
}
public event Action OnElapsed;
}
Add the service to the DI container, in the Program.Main method, as transient:
builder.Services.AddTransient(config =>
{
var blazorTimer = new BlazorTimer();
blazorTimer.SetTimer(1000);
return blazorTimer;
});
@page "/"
@implements IDisposable
@inject BlazorTimer Timer
@count.ToString()
@code{
private int count = 0;
protected override void OnInitialized()
{
Timer.OnElapsed += NotifyTimerElapsed;
base.OnInitialized();
}
private void NotifyTimerElapsed()
{
// Note: WebAssembly Apps are currently supporting a single thread, which
// is why you don't have to call
// the StateHasChanged method from within the InvokeAsync method. But it
// is a good practice to do so in consideration of future changes, such as
// ability to run WebAssembly Apps in more than one thread.
InvokeAsync(() => { count++; StateHasChanged(); });
}
public void Dispose()
{
Timer.OnElapsed -= NotifyTimerElapsed;
}
}
However, I'm told that
the BlazorTimer is leaking the _timer. Timer is IDisposable
Does unsubscribing the event handler in the Dispose method implemented in a Blazor component causes the BlazorTimer leaking the _timer. Actually I do not entirely understand "the BlazorTimer is leaking the _timer. Timer is IDisposable" , so let me ask, how can I prevent the leaking of the timer, and yet use code to unsubscribe the event handler in the Dispose method implemented in a Blazor component ? Is there any way to prevent this leaking other than skipping the un-subscription of the event handler.
Ok, I've solved the issue thanks to mkArtakMSFT and Peter Morris.
The general rule of thumb is that every time you encapsulate a disposable type in a new type as a member, you should make your new type disposable too. In your particular case, the BlazorTimer class is not disposable - hence the underlying _timer instance, when initialized, never gets disposed of - leaving some memory behind.
Furthermore, every time the SetTimer method is called, a new Timer instance is being created, and the old one is being left behind (in the air), again leaking memory. Consider disposing of existing instance, if that's your intent. Or, even better, reuse existing instance if that would be acceptable for your business rules Source
Note: "the BlazorTimer class is not disposable" because I'm using transient dependencies. Implementing it as disposable would have adverse effects... See explanation blazor-university
To solve the leaking memory, in my current code snippet, I should simply call the Dispose method (always do that, this time forgot it) on the Timer object from the NotifyTimerElapsed method