Blazor Server CancellationToken attached to circuit
- Dominant language
- C#
- Stars
- 38.4k
- Forks
- 10.9k
- Avg merge
- 2d 10h
- Merged PRs (30d)
- 281
Description
### Is there an existing issue for this?
- [x] I have searched the existing issues
### Is your feature request related to a problem? Please describe the problem.
What I'm trying to achieve is the same that we can achieve by using `HttpContext.RequestAborted`, it would be good if we can cancel any operation that is "already lost" due to disconnection ou user intentional disconnect at Blazor Server.
Couldn't find a built-in implementation or any examples at Microsoft documentation.
### Describe the solution you'd like
The idea behind it is to have the same behavior of `HttpContext.RequestAborted`.
An api that we can rely once there is some kind of disconnection by providing a cancellation token that we can use at the blazor components.
> Maybe some kind of `Circuit.Current.IsCancellationRequested` thing.
Since this is usually a common "built-in feature", such as the ones provided in HttpContext, Background Services, it would be nice to have one attached to Blazor Server Circuit.
Would be also good to have it linked to a global CancellationTokenSource of the app _(such as the ones that we rely on `BackgroundService`/`IHostedService`)_ that cancels all connected circuits.
### Additional context
A simple solution could be done using a scoped circuit handler. But not as good as I would like to be.
Since there are two main events: a lost of connection and full disconnect (aka down). I had to do some workaround to handle both, when there connection is lost it keeps the scoped `CircuitConnectionState` instance however, at this point I should cancel any running operation because the user has already "lost the request" and it will be a waste of resource until it reconnects:
```csharp
public class CircuitConnectionState
{
private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
public CancellationToken CancellationToken => _cancellationTokenSource.Token;
public void Reconnected()
{
if (_cancellationTokenSource.IsCancellationRequested)
{
_cancellationTokenSource.Dispose();
_cancellationTokenSource = new CancellationTokenSource();
}
}
public void Disconnected()
{
_cancellationTokenSource.Cancel();
}
}
```
```csharp
public class CancellationCircuitHandler : CircuitHandler
{
private readonly CircuitConnectionState _state;
public CancellationCircuitHandler(CircuitConnectionState state)
{
_state = state;
}
public override Task OnCircuitOpenedAsync(Circuit circuit, CancellationToken cancellationToken)
{
_state.Reconnected(); //Should be useless
return base.OnCircuitOpenedAsync(circuit, cancellationToken);
}
public override Task OnConnectionUpAsync(Circuit circuit, CancellationToken cancellationToken)
{
_state.Reconnected();
return base.OnConnectionUpAsync(circuit, cancellationToken);
}
public override Task OnConnectionDownAsync(Circuit circuit, CancellationToken cancellationToken)
{
_state.Disconnected();
return base.OnConnectionDownAsync(circuit, cancellationToken);
}
public override Task OnCircuitClosedAsync(Circuit circuit, CancellationToken cancellationToken)
{
_state.Disconnected();
return base.OnCircuitClosedAsync(circuit, cancellationToken);
}
}
```
DI at `Program.cs`:
```
builder.Services.AddScoped();
builder.Services.AddScoped();
```
If there is any other suggestion or a better implementation, please share.
Contributor guide
Research direction
Start by reading the CircuitHandler lifecycle methods named in the issue, especially OnConnectionDownAsync, OnConnectionUpAsync, and OnCircuitClosedAsync. Review the Program.cs registrations and the CancellationCircuitHandler and CircuitConnectionState workaround. Done means an agreed built-in cancellation API addresses connection loss, reconnection, circuit closure, and the proposed app-wide cancellation behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- api, backend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100