我们有一个 .Net Core 6 应用程序,我们正在使用 Blazor 服务器组件慢慢将 UI 功能从 JS 过渡到 Blazor。在大多数情况下,一切都工作正常,但是我们引入了几个组件,它们具有计时器,用于刷新可以在用户操作之外更改的项目状态,例如网络状态。一切工作正常,除了当离开组件所在的页面时,组件的 Dispose 方法永远不会被调用,这会使计时器继续运行。
以下是从 cshtml 页面调用该组件的方式:
<component type="typeof(APStatus)" render-mode="Server" /\>
这是 OnInitializedAsync 中的计时器定义。
_timer = new System.Timers.Timer(10000);
_timer.Elapsed += CountDownTimer;
_timer.Start();
_timer.Enabled = true;
这是 CountDownTimer 回调:
public async void CountDownTimer(Object source, System.Timers.ElapsedEventArgs e)
{
if (_internalCounter > 0)
{
_internalCounter -= 1;
}
else
{
_timer.Enabled = false;
_timer.Stop();
}
await InvokeAsync(async () =>
{
if (NetInfo != null)
{
await GetApStatus();
}
});
}
这是处置方法:
public void Dispose()
{
System.Diagnostics.Debug.WriteLine("Disposing Happened");
_timer.Enabled = false;
_timer.Stop();
_timer.Dispose();
_timer = null;
}
我添加了一个 CircuitHandler,同样的问题,我收到 OnCircuitOpenAsync 事件,但闭路从未触发。
这是一些 CircuitHandler 代码:
public override Task OnCircuitClosedAsync(Circuit circuit, CancellationToken cancellationToken)
{
Console.WriteLine("OnCircuitClosedAsync");
Circuits.TryRemove(circuit.Id, out var circuitRemoved);
OnCircuitsChanged();
return base.OnCircuitClosedAsync(circuit, cancellationToken);
}
我几乎尝试了我能想到的所有方法,通过了 Program.cs,调用组件的各种方式,从 chrome 开发工具的角度来看,一切似乎都工作正常,日志中没有奇怪的错误消息。
我打开了 Blazor 日志记录,但没有显示任何内容。
我几乎搜索了所有能找到的论坛,寻找有类似问题的人,但找不到任何关于为什么会发生这种情况的信息。
我现场还有其他 blazor 组件,一切正常。我已将 Dispose 添加到所有这些中,并且没有一个被解雇。
我已更新到最新的 .net core 6 软件包,但没有成功。
我开始了一个新项目,并在 blazor 组件中实现了计时器的 Microsoft 代码,它工作正常,在离开页面时按预期调用 Dispose。
当我将该组件复制到我们的项目中时,一切正常,但是当我离开打开该组件的页面时,什么也没有,Dispose 永远不会被调用。
这是计数器示例:
@page "/counter"
@using System.Timers
@using System.Diagnostics
@implements IDisposable
<PageTitle\>Counter\</PageTitle\>
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<p>Current count: @timerCount</p>
<button class="btn btn-primary" @onclick="IncrementCount"\>Click me\</button\>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
private int timerCount = 0;
private Timer timer = new(1000);
protected override void OnInitialized()
{
timer.Elapsed += (sender, eventArgs) => OnTimerCallback();
timer.Start();
}
private void OnTimerCallback()
{
_ = InvokeAsync(() =>
{
timerCount++;
StateHasChanged();
});
}
public void Dispose()
{
Debug.WriteLine("Disposing");
timer.Dispose();
}
}
经过大量研究和调整主要与电路相关的内容后,我在 Program.cs 中使用它设置了 DisconnectedCircuitRetentionPeriod
builder.Services.AddServerSideBlazor().AddCircuitOptions(options =>
{
options.DetailedErrors = true;
options.DisconnectedCircuitRetentionPeriod = TimeSpan.FromSeconds(10);
});
处理时间从大约 3.5 分钟缩短到 10 秒或更短。仍在努力理解为什么这是必要的,但似乎是进步。
测试此组件以及网站上的所有其他 blazor 组件后,这似乎已经解决了问题,并且似乎没有引起任何其他问题。做了更多研究后
我也发现了这个问题和答案,似乎表明它可以解决此类处理组件的问题。
我不确定为什么在某些情况下尝试处理时这种情况并不常见。我希望这对其他人有帮助。
解决方案是将其添加到 Program.cs 中
.AddCircuitOptions(options =>
{
options.DetailedErrors = true;
options.DisconnectedCircuitRetentionPeriod = TimeSpan.FromSeconds(0);
options.DisconnectedCircuitMaxRetained = 0;
});
看起来保留期默认为 3 分钟,这与最终调用 Dispose 所需的时间一致。
正如上次更新中提到的,我发现了这个问题和答案,这似乎表明它可以解决此类组件处置问题。