Blazor - Progress Indicator - Timer Object

S Chapman 82 41 Reputation points
2021-01-22T13:13:55.287+00:00

I have a requirement to display the progress of jobs on an application server in a Blazor Server app. Currently I'm using a timer to poll the database for progress and display the results to the user. I have no control over the app server and can't change it so have to stick to polling.

My question is how do I stop the timer when the user closes the page and moves away to a different razor component (page)?

Blazor
Blazor
A free and open-source web framework that enables developers to create web apps using C# and HTML being developed by Microsoft.
1,595 questions
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Michael Wang-MSFT 1,061 Reputation points
    2021-01-26T09:21:34.253+00:00

    Hi, @S Chapman 82 ,

    You could try implement a CircuitHandler on your page to monitor event of closing page .

    CircuitHandler enables you to react to lifecycle events for the Circuit, which is the backbone of a Blazor Server connection.

    Methods
    OnCircuitClosedAsync(Circuit, CancellationToken)
    Invoked when a new circuit is being discarded.

    OnCircuitOpenedAsync(Circuit, CancellationToken)
    Invoked when a new circuit was established.

    OnConnectionDownAsync(Circuit, CancellationToken)
    Invoked when a connection to the client was dropped.

    OnConnectionUpAsync(Circuit, CancellationToken)
    Invoked when a connection to the client was established. - This method is executed once initially after OnCircuitOpenedAsync(Circuit, CancellationToken) and once each for each reconnect during the lifetime of a circuit.

    Step 1 CircuitHandlerService

    using Microsoft.AspNetCore.Components.Server.Circuits;  
    using System;  
    using System.Collections.Concurrent;  
    using System.Threading;  
    using System.Threading.Tasks;  
      
      
    namespace BlazorCircuitHandler.Services  
    {  
        public class CircuitHandlerService : CircuitHandler  
        {  
            public ConcurrentDictionary<string, Circuit> Circuits { get;   
                set; }  
            public event EventHandler CircuitsChanged;  
      
            protected virtual void OnCircuitsChanged()  
                 => CircuitsChanged?.Invoke(this, EventArgs.Empty);  
      
            public CircuitHandlerService()  
            {  
                 Circuits = new ConcurrentDictionary<string, Circuit>();  
            }  
      
            public override Task OnCircuitOpenedAsync(Circuit circuit,   
                                 CancellationToken cancellationToken)  
           {  
                 Circuits[circuit.Id] = circuit;  
                 OnCircuitsChanged();  
                 return base.OnCircuitOpenedAsync(circuit,   
                                       cancellationToken);  
           }  
      
           public override Task OnCircuitClosedAsync(Circuit circuit,   
                     CancellationToken cancellationToken)  
          {  
               Circuit circuitRemoved;  
               Circuits.TryRemove(circuit.Id, out circuitRemoved);  
               OnCircuitsChanged();  
               return base.OnCircuitClosedAsync(circuit,   
                                 cancellationToken);  
          }  
      
          public override Task OnConnectionDownAsync(Circuit circuit,   
                                CancellationToken cancellationToken)  
          {  
              return base.OnConnectionDownAsync(circuit,   
                               cancellationToken);  
          }  
      
          public override Task OnConnectionUpAsync(Circuit circuit,   
                              CancellationToken cancellationToken)  
          {  
              return base.OnConnectionUpAsync(circuit, cancellationToken);  
          }  
       }  
     }  
    

    Step 2 Implement in your page

    @page "/"  
      
    @using Microsoft.AspNetCore.Components.Server.Circuits  
    @using BlazorCircuitHandler.Services  
      
    @inject CircuitHandler circuitHandler  
    @implements IDisposable  
      
      
      
    <h1>Hello, world!</h1>  
      
    Welcome to your new app.  
      
    <p>  
     Number of Circuits: @((circuitHandler as   
     BlazorCircuitHandler.Services.CircuitHandlerService).Circuits.Count)  
     <ul>  
        @foreach (var circuit in (circuitHandler as   
         BlazorCircuitHandler.Services.CircuitHandlerService).Circuits)  
        {  
            <li>@circuit.Key</li>  
        }  
     </ul>  
    </p>  
      
    @code {  
       protected override void OnInitialized()  
       {  
           // Subscribe to the event handler  
        (circuitHandler as CircuitHandlerService).CircuitsChanged +=   
             HandleCircuitsChanged;  
          
        }  
      
     public void Dispose()  
     {  
        // Unsubscribe the event handler when the component is disposed  
        (circuitHandler as CircuitHandlerService).CircuitsChanged -=   
          HandleCircuitsChanged;  
         
     }  
      
     public void HandleCircuitsChanged(object sender, EventArgs args)  
     {  
        // notify the component that its state has changed   
        // Important: You must use InvokeAsync  
        InvokeAsync(() => StateHasChanged());  
     }  
    }  
    

    Step 3 inject CircuitHandlerService to container

            public void ConfigureServices(IServiceCollection services)  
            {  
                services.AddRazorPages();  
                services.AddServerSideBlazor();  
      
                services.AddSingleton<CircuitHandler>(new CircuitHandlerService());  
            }  
    

    ------
    If the answer doesn’t solve your issue, please provide more details of error that will help us track down what’s happening.
    If the answer is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    Best Regards,
    Michael Wang

    1 person found this answer helpful.
    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.