【发布时间】:2021-11-14 20:42:24
【问题描述】:
免责声明:我对 C#、ASP.NET Core 和依赖注入领域非常陌生。我从默认模板创建了一个简单的 Blazor Server 应用程序,该模板构建了一个模拟天气服务,并在表格中显示了从中获取的数据。现在我希望表格每五秒自动更新一次,为此我使用了Hangfire.AspNetCore 和Hangfire.MemoryStorage 包。所以我稍微修改了FetchData.razor 组件,看起来像这样:
@page "/fetchdata"
@using WeatherTest.Data
@using Hangfire
@inject WeatherForecastService ForecastService
<h1>Weather forecast</h1>
<p>This component demonstrates fetching data from a service.</p>
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@code {
private WeatherForecast[] forecasts;
public async Task UpdateForecasts()
{
forecasts = await ForecastService.GetForecastAsync(DateTime.Now);
BackgroundJob.Schedule(() => UpdateForecasts(), TimeSpan.FromSeconds(5));
}
protected override async Task OnInitializedAsync()
{
await UpdateForecasts();
}
}
这是气象服务:
using System;
using System.Linq;
using System.Threading.Tasks;
namespace WeatherTest.Data
{
public class WeatherForecastService
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
public Task<WeatherForecast[]> GetForecastAsync(DateTime startDate)
{
var rng = new Random();
return Task.FromResult(Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = startDate.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
}).ToArray());
}
}
}
以及服务配置:
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddSingleton<WeatherForecastService>();
services.AddHangfire(c => c.UseMemoryStorage());
services.AddHangfireServer();
}
问题是UpdateForecasts()在OnInitializedAsync()调用时成功,但在Hangfire调用时失败,在forecasts = await ForecastService.GetForecastAsync(DateTime.Now);抛出以下异常:
System.NullReferenceException: '对象引用未设置为 对象的实例。'
WeatherTest.Pages.FetchData.ForecastService.get 返回 null。
在我看来,由于 Hangfire 工作程序在另一个线程中运行,因此 WeatherForecastService 不会被注入。我对吗?是否可以从多个线程中使用单例,或者每个线程都应该有自己的服务实例?最后,我应该如何解决这个问题?
【问题讨论】:
-
我认为您遗漏了一部分信息。在调度后台作业时,在这种情况下,用户正在主线程上操作,而您的作业在另一个线程中执行。你正在做一个即发即弃的工作,你正在安排它并说再见。我认为可能可行的一种方法是创建一个事件并在页面本身内订阅它,然后在更新时从 WeatherService 引发该事件。
-
在这种情况下您可以使用简单的计时器服务,但我猜还有其他原因可以尝试使用 hangfire?为此,您需要 hangfire 来获取服务引用并直接与服务交互,然后使用上面建议的事件。没有任何使用 Hangfire 的经验,我会让其他人告诉你是否/如何做。
-
@Dennisv.W.谢谢丹尼斯。我想我知道这一点,并计划在工作例程中检查连接是否仍然存在;如果没有,只需取消作业并停止调度它。关于您的建议,即使没有连接的客户端,这不会使服务自行更新吗?只有当有用户查看
FetchData.razor组件时,我才想要求更新。此外,服务返回的数据对于每个用户应该是不同的,尽管在本示例中并非如此。 -
@MrCakaShaunCurtis 谢谢。实际上我只是在寻找最简单的方法来做到这一点,所以如果根本不需要的话,我可以放弃 Hangfire!
标签: c# asp.net-core blazor blazor-server-side hangfire