检测客户端关闭连接 Blazor
Detect client closing connection Blazor
我有一个循环,在客户端访问页面的整个过程中我都有 运行,但我无法关闭循环,因此即使用户已经断开连接。是否有在用户关闭连接时运行的生命周期方法?还是有其他方法?
如果这是正在处理的单个页面,让页面继承 OwningComponentBase
(首选)或实现 IDisposable
,然后使用退出标志设置循环,或者如果它是循环task 在任务上设置了一个 CancellationTokenSource
和 token。然后,当用户离开页面并且页面关闭时,覆盖 Dispose
方法并翻转退出标志或将令牌源设置为 'Cancelled' 并且您的循环应该退出。
如果您需要更深入,This Link 文档中讨论的服务器端电路可能会有所帮助。对于客户端,如果 运行 在浏览器中使用,dispose 方法应该有效,但是如果你有一个服务器端进程通过 API 启动,你需要让它 运行 它当然因为会话的客户端将处于故障状态,如果您使用 JWT,则令牌将有自己的到期时间并且服务器不会参与。我建议在需要时建立超时作为保障。
我不确定仅实现 IDisposable 接口是否可以帮助您,但实现 Blazor Server circuit handler 可能。我依稀记得在 Whosebug 中有人问过与你类似的问题......OP 试图实现 IDisposable 接口,但无济于事。我已经回答过一两次这个问题和一个后续问题...我正在发布我的答案中的代码,希望这对您有所帮助...
CircuitHandlerService.cs
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)
{
Console.WriteLine("OnCircuitClosedAsync");
Circuit circuitRemoved;
Circuits.TryRemove(circuit.Id, out circuitRemoved);
OnCircuitsChanged();
return base.OnCircuitClosedAsync(circuit, cancellationToken);
}
public override Task OnConnectionDownAsync(Circuit circuit,
CancellationToken cancellationToken)
{
Console.WriteLine("OnConnectionDownAsync");
return base.OnConnectionDownAsync(circuit, cancellationToken);
}
public override Task OnConnectionUpAsync(Circuit circuit,
CancellationToken cancellationToken)
{
return base.OnConnectionUpAsync(circuit, cancellationToken);
}
}
}
用法
@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()
{
// register event handler
(circuitHandler as CircuitHandlerService).CircuitsChanged +=
HandleCircuitsChanged;
}
public void Dispose()
{
// unregister the event handler when the component is destroyed
(circuitHandler as CircuitHandlerService).CircuitsChanged -=
HandleCircuitsChanged;
}
public void HandleCircuitsChanged(object sender, EventArgs args)
{
// notify the UI that the state has changed
InvokeAsync(() => StateHasChanged());
}
}
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// ........ .....
services.AddSingleton<CircuitHandler>(new CircuitHandlerService());
}
我有一个循环,在客户端访问页面的整个过程中我都有 运行,但我无法关闭循环,因此即使用户已经断开连接。是否有在用户关闭连接时运行的生命周期方法?还是有其他方法?
如果这是正在处理的单个页面,让页面继承 OwningComponentBase
(首选)或实现 IDisposable
,然后使用退出标志设置循环,或者如果它是循环task 在任务上设置了一个 CancellationTokenSource
和 token。然后,当用户离开页面并且页面关闭时,覆盖 Dispose
方法并翻转退出标志或将令牌源设置为 'Cancelled' 并且您的循环应该退出。
如果您需要更深入,This Link 文档中讨论的服务器端电路可能会有所帮助。对于客户端,如果 运行 在浏览器中使用,dispose 方法应该有效,但是如果你有一个服务器端进程通过 API 启动,你需要让它 运行 它当然因为会话的客户端将处于故障状态,如果您使用 JWT,则令牌将有自己的到期时间并且服务器不会参与。我建议在需要时建立超时作为保障。
我不确定仅实现 IDisposable 接口是否可以帮助您,但实现 Blazor Server circuit handler 可能。我依稀记得在 Whosebug 中有人问过与你类似的问题......OP 试图实现 IDisposable 接口,但无济于事。我已经回答过一两次这个问题和一个后续问题...我正在发布我的答案中的代码,希望这对您有所帮助...
CircuitHandlerService.cs
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)
{
Console.WriteLine("OnCircuitClosedAsync");
Circuit circuitRemoved;
Circuits.TryRemove(circuit.Id, out circuitRemoved);
OnCircuitsChanged();
return base.OnCircuitClosedAsync(circuit, cancellationToken);
}
public override Task OnConnectionDownAsync(Circuit circuit,
CancellationToken cancellationToken)
{
Console.WriteLine("OnConnectionDownAsync");
return base.OnConnectionDownAsync(circuit, cancellationToken);
}
public override Task OnConnectionUpAsync(Circuit circuit,
CancellationToken cancellationToken)
{
return base.OnConnectionUpAsync(circuit, cancellationToken);
}
}
}
用法
@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()
{
// register event handler
(circuitHandler as CircuitHandlerService).CircuitsChanged +=
HandleCircuitsChanged;
}
public void Dispose()
{
// unregister the event handler when the component is destroyed
(circuitHandler as CircuitHandlerService).CircuitsChanged -=
HandleCircuitsChanged;
}
public void HandleCircuitsChanged(object sender, EventArgs args)
{
// notify the UI that the state has changed
InvokeAsync(() => StateHasChanged());
}
}
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// ........ .....
services.AddSingleton<CircuitHandler>(new CircuitHandlerService());
}