我编写了一个程序,可以使用 Blazor 服务器应用定期更新页面。
执行该程序时,每秒都会获取当前时间和数据库表中的值并显示在页面上,但该计时器中的处理会在一定时间后停止。
虽然测量不准确,但计时器中的处理会在大约 10 到 30 分钟后停止。
但是我看浏览器的debug工具并没有报错,在Visual Studio上也没有报错。
我搜索了这样的示例,但找不到它,也无法确定是什么原因造成的。
我希望此计时器中的处理能够正常工作,直到我明确将其指定为停止为止。
这可能是什么原因造成的? 我遇到麻烦了,因为我不知道原因。 请给我一些建议。 谢谢。
private string Time { get; set; }
protected override void OnInitialized()
{
var timer = new System.Threading.Timer((_) =>
{
Time = DateTime.Now.ToString();
InvokeAsync(() =>
{
// Get the value from the database
databaseValue = TimerProcessGetValue();
StateHasChanged();
});
}, null, 0, 1000);
base.OnInitialized();
}
定时器中调用的进程
public async Task<int?> TimerProcessGetValue()
{
int? timerProcessValue;
using(DbContext = DbFactory.CreateDbContext())
{
timerProcessValue = dbContext.TestTable.Single(x => x.Id == 1).TestValue;
}
return timerProcessValue;
}
后记
目标组件的全文。
PageRefleshTest.cs
@page "/refresh-ui-manually"
@using System.Threading;
@using TestBlazorServer.Models;
@using Microsoft.EntityFrameworkCore;
@inject IDbContextFactory<SQLbeginnerContext> DbFactory
<h1>@Time</h1>
<h1>TestValue:@databaseValue</h1>
private string Time { get; set; }
private int? databaseValue { get; set; }
protected override void OnInitialized()
{
var timer = new System.Threading.Timer((_) =>
{
Time = DateTime.Now.ToString();
InvokeAsync(() =>
{
// Get the value from the database
databaseValue = TimerProcessGetValue().Result;
StateHasChanged();
});
}, null, 0, 1000);
base.OnInitialized();
}
public async Task<int?> TimerProcessGetValue()
{
int? timerProcessValue;
using (var dbContext = DbFactory.CreateDbContext())
{
timerProcessValue = dbContext.TestTable.Single(x => x.Id == 1).TestValue;
}
return timerProcessValue;
}
使用System.Timers.Timer实现
@page "/Refresh2"
@inject IDbContextFactory<SQLbeginnerContext> DbFactory
@using TestBlazorServer.Models
@using Microsoft.EntityFrameworkCore
@using System.Timers
@implements IDisposable
<h3>PageRefresh2</h3>
<h1>@Time</h1>
<h1>@currentCount</h1>
<h1>TestValue:@databaseValue/h1>
@code {
private int currentCount = 0;
private Timer timer2 = new(1000);
private string Time { get; set; }
private int? databaseValue { get; set; }
protected override void OnInitialized()
{
timer2.Elapsed += (sender, eventArgs) => OnTimerCallback();
timer2.Start();
}
private void OnTimerCallback()
{
_ = InvokeAsync(() =>
{
currentCount++;
Time = DateTime.Now.ToString();
databaseValue = TimerProcessGetValue().Result;
StateHasChanged();
});
}
public void Dispose() => timer2.Dispose();
public async Task<int?> TimerProcessGetValue()
{
int? timerProcessValue;
await using (var dbContext = DbFactory.CreateDbContext())
{
timerProcessValue = dbContext.TestTable.Single(x => x.Id == 1).TestValue;
}
return timerProcessValue;
}
}
最佳答案
这当然可能是由于 SignalR 连接失败造成的。不过,这应该会重新连接。
这里的主要嫌疑人是.Result
。您应该始终避免异步代码中的 .Wait()
和 .Result
。 Aslo,您的数据库方法并不是真正的异步,这也可能发挥作用。
但是“半小时”也可能来自垃圾收集器抛出的 Timer 对象。参见this page上的紫色注释。当您有一个计时器时,您应该将其锚定在一个字段中并对其进行 Dispose()。
下一步是使事件处理程序成为async void
,这是极少数需要的情况之一。然后只调用 StatehasChanged 调用。
@implements IDisposable
...
@code {
System.Threading.Timer _timer; // use a private field
protected override void OnInitialized()
{
_timer = new System.Threading.Timer(async (_) =>
{
Time = DateTime.Now.ToString();
databaseValue = await TimerProcessGetValue();
await InvokeAsync(StateHasChanged);
}, null, 0, 1000);
// base.OnInitialized(); -- not needed
}
public void Dispose()
{
_timer?.Dispose();
}
}
并使 Db 操作实际上异步:
public async Task<int?> TimerProcessGetValue()
{
int? timerProcessValue;
using (var dbContext = DbFactory.CreateDbContext())
{
timerProcessValue =
(await dbContext.TestTable.SingleAsync(x => x.Id == 1))
.TestValue;
}
return timerProcessValue;
}
只有您可以现场测试此功能,请告诉我们它是否有效。
关于c# - Blazor 服务器计时器停止页面更新的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69418287/