Skip to content

Commit

Permalink
Improve SignalR idle timeout example (#32027)
Browse files Browse the repository at this point in the history
  • Loading branch information
guardrex authored Mar 11, 2024
1 parent 42ce542 commit 83204f4
Showing 1 changed file with 36 additions and 13 deletions.
49 changes: 36 additions & 13 deletions aspnetcore/blazor/fundamentals/signalr.md
Original file line number Diff line number Diff line change
Expand Up @@ -650,27 +650,43 @@ By default, components are prerendered on the server before the client connectio

Monitor inbound circuit activity using the <xref:Microsoft.AspNetCore.Components.Server.Circuits.CircuitHandler.CreateInboundActivityHandler%2A> method on <xref:Microsoft.AspNetCore.Components.Server.Circuits.CircuitHandler>. Inbound circuit activity is any activity sent from the browser to the server, such as UI events or JavaScript-to-.NET interop calls.

For example, you can use a circuit activity handler to detect if the client is idle:
For example, you can use a circuit activity handler to detect if the client is idle and log its circuit ID (<xref:Microsoft.AspNetCore.Components.Server.Circuits.Circuit.Id?displayProperty=nameWithType>):

```csharp
using Microsoft.AspNetCore.Components.Server.Circuits;
using Microsoft.Extensions.Options;
using Timer = System.Timers.Timer;

public sealed class IdleCircuitHandler : CircuitHandler, IDisposable
{
readonly Timer timer;
readonly ILogger logger;
private Circuit? currentCircuit;
private readonly ILogger logger;
private readonly Timer timer;

public IdleCircuitHandler(IOptions<IdleCircuitOptions> options,
ILogger<IdleCircuitHandler> logger)
public IdleCircuitHandler(ILogger<IdleCircuitHandler> logger,
IOptions<IdleCircuitOptions> options)
{
timer = new Timer();
timer.Interval = options.Value.IdleTimeout.TotalMilliseconds;
timer.AutoReset = false;
timer = new Timer
{
Interval = options.Value.IdleTimeout.TotalMilliseconds,
AutoReset = false
};

timer.Elapsed += CircuitIdle;
this.logger = logger;
}

private void CircuitIdle(object? sender, System.Timers.ElapsedEventArgs e)
{
logger.LogInformation("{Circuit} is idle", nameof(CircuitIdle));
logger.LogInformation("{CircuitId} is idle", currentCircuit?.Id);
}

public override Task OnCircuitOpenedAsync(Circuit circuit,
CancellationToken cancellationToken)
{
currentCircuit = circuit;

return Task.CompletedTask;
}

public override Func<CircuitInboundActivityContext, Task> CreateInboundActivityHandler(
Expand All @@ -680,14 +696,12 @@ public sealed class IdleCircuitHandler : CircuitHandler, IDisposable
{
timer.Stop();
timer.Start();

return next(context);
};
}

public void Dispose()
{
timer.Dispose();
}
public void Dispose() => timer.Dispose();
}

public class IdleCircuitOptions
Expand All @@ -703,18 +717,27 @@ public static class IdleCircuitHandlerServiceCollectionExtensions
{
services.Configure(configureOptions);
services.AddIdleCircuitHandler();

return services;
}

public static IServiceCollection AddIdleCircuitHandler(
this IServiceCollection services)
{
services.AddScoped<CircuitHandler, IdleCircuitHandler>();

return services;
}
}
```

Register the service in the `Program` file. The following example configures the default idle timeout of five minutes to five seconds in order to test the preceding `IdleCircuitHandler` implementation:

```csharp
builder.Services.AddIdleCircuitHandler(options =>
options.IdleTimeout = TimeSpan.FromSeconds(5));
```

Circuit activity handlers also provide an approach for accessing scoped Blazor services from other non-Blazor dependency injection (DI) scopes. For more information and examples, see:

* <xref:blazor/fundamentals/dependency-injection#access-server-side-blazor-services-from-a-different-di-scope>
Expand Down

0 comments on commit 83204f4

Please sign in to comment.