【发布时间】:2021-11-26 05:31:00
【问题描述】:
在 Blazor Server 中添加了每秒更新数据的过程。
这工作正常,但是当我在浏览器中按刷新页面 (F5) 时,我收到以下错误:
System.ObjectDisposedException: 'Cannot process pending renders after the renderer has been disposed.
ObjectDisposed_ObjectName_Name'
目标代码在这里
@code {
private List<Models.Recipe> recipes { get; set; }
private List<Models.NowOrder> nowOrders { get; set; }
private List<Models.PlanOrder> planOrders { get; set; }
System.Threading.Timer _timer;
protected override void OnInitialized()
{
using (var dbContext = DbFactory.CreateDbContext())
{
this.recipes = dbContext.Recipes.ToList();
this.planOrders = dbContext.PlanOrders.ToList();
this.nowOrders = dbContext.NowOrders.ToList();
}
_timer = new System.Threading.Timer(async (_) =>
{
Time = DateTime.Now.ToString();
databaseValue = await TimerProcessGetValue();
await InvokeAsync(StateHasChanged);
}, null, 0, 1000);
}
public void Dispose()
{
_timer?.Dispose();
}
public async Task<int?> TimerProcessGetValue()
{
int? timerProcessValue;
using (var dbContext = DbFactory.CreateDbContext())
{
timerProcessValue = (await dbContext.TestTable.SingleAsync(x => x.Id == 1)).TestValue;
}
return timerProcessValue;
}
}
刷新页面时“await InvokeAsync(StateHasChanged);”
如果注释掉以下部分,即使按F5键也不会报错,所以我认为我对异步处理的处理是错误的,但是我很困扰,因为我什至找不到相同的情况如果我搜索我的错误。
您认为这是什么原因? 感谢您的合作。
_timer = new System.Threading.Timer(async (_) =>
{
Time = DateTime.Now.ToString();
databaseValue = await TimerProcessGetValue();
await InvokeAsync(StateHasChanged);
}, null, 0, 1000);
更改为验证码
_timer = new System.Threading.Timer(async (_) =>
{
Time = DateTime.Now.ToString();
//databaseValue = await TimerProcessGetValue();
await Task.Delay(500); //Added verification code.
await InvokeAsync(StateHasChanged);
}, null, 0, 1000);
}
追加。(2021 年 10 月 10 日)
使用的版本:net core 5.0.7。
使用的浏览器:Edge。
我没有使用任何其他浏览器。
我的环境有限,只能用Edge……
以下是我们已验证的三个代码。
①这是一个使用Dispose(WaitHandle)的例子。
这并没有改善错误。
public void Dispose()
{
using(System.Threading.WaitHandle waitHandle = new System.Threading.ManualResetEvent(false))
{
if (_timer.Dispose(waitHandle))
{
const int millisecondsTimeout = 500;
if (!waitHandle.WaitOne(millisecondsTimeout))
{
System.Diagnostics.Debug.WriteLine("Dispose Test");
}
}
}
}
②这是一个使用 System.Timers.Timer 的例子。
使用 F5 键重新加载成功。
private int currentCount = 0;
private Timer timer2 = new(1000);
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();
③增加错误处理。
即使使用这种方法,我也成功地使用 F5 键重新加载,没有任何错误。
try
{
_timer = new System.Threading.Timer(async (_) =>
{
Time = DateTime.Now.ToString();
databaseValue = await TimerProcessGetValue();
await InvokeAsync(StateHasChanged);
}, null, 0, 1000);
}
catch
{
// empty on purpose
}
【问题讨论】:
-
你在标记部分使用
@implements IDisposable吗? -
你能通过将
databaseValue = await TimerProcessGetValue();替换为Task.Delay(500);来创建minimal reproducible example 吗?因为我无法重现此错误。用一个新的普通项目做到这一点。 -
抱歉信息不足。是的,我正在使用@implements IDisposable。
-
非常感谢。添加了验证码。如果我没有达到我想做的事,我很抱歉。但是,通过用这个 await Task.Delay (500) ; 替换它,可以正常执行页面重新加载。这是为什么...
-
这意味着它是由 TimerProcessGetValue() 以某种方式引起的。
标签: c# blazor blazor-server-side