Проблема, связанная с Внешний вызов методов компонента для обновления состояния .
Итак, у меня есть компонент, который должен отображать данные, полученные через обработчик событий. Событие инициируется службой, которая зарегистрирована как одиночная. Это событие вызывается, когда метод-концентратор SignalR вызывается из клиента.
Компонент, который отображает данные, поддерживает несколько CulturInfo. Теперь проблема в том, что CulturInfo, с помощью которого компонент перерисовывается при получении новых данных, является CultureInfo потока, который инициирует событие в одноэлементном сервисе.
Некоторый код и подробное описание:
Каждый клиент может отправить информацию о здоровье, вызвав ReceiveHealthInfo(HealthModel healthInfo)
в концентраторе SignalR. Это вызовет метод HealthService.UpdateStatusInfo(string monitorId, HealthModel info)
. HealthService вызовет событие StatusUpdated
. Компонент прослушивает это событие, обрабатывает данные и вызывает StateHasChanged
асинхронно при возникновении события. Теперь компонент обновляет страницу с обновленными данными. И страница отображается с CultureInfo потока, который вызвал событие StatusUpdated
.
Почему это происходит? Вызов InvokeAsync(StateHasChanged)
в компоненте не является действием, отправляемым потоку, которому принадлежит компонент. Не следует ли компоненту повторно выполнить рендеринг с помощью CultureInfo, с помощью которого компонент отображался в первый раз?
При форсировании CurrentUICulture в HealthService компонент выполняет визуализацию с этим принудительным CurrentUICulture.
Я что-то здесь не так ? Заранее большое спасибо.
Компонент: HealthMonitor.razor.cs
sealed public partial class HealthMonitor : IDisposable
{
private List<HealthModel> data { get; set; } = new List<HealthModel>();
[Inject]
private HealthService healthService { get; set; }
[Inject]
private IStringLocalizer<HealthMonitor> stringLocalizer { get; set; }
protected override Task OnInitializedAsync()
{
healthService.StatusUpdated += HealthService_StatusUpdated;
return base.OnInitializedAsync();
}
private async Task HealthService_StatusUpdated(HealthModel[] healthModel)
{
await InvokeAsync(() =>
{
data = healthModel.ToList();
StateHasChanged();
});
}
public void Dispose()
{
healthService.StatusUpdated -= HealthService_StatusUpdated;
}
}
Singleton service: HealthService
internal class HealthService
{
public event Func<HealthModel[], Task> StatusUpdated;
public HealthStates State { get; private set; }
public ConcurrentDictionary<string, HealthModel> HealthInfo { get; private set; } = new ConcurrentDictionary<string, HealthModel>();
private readonly ILogger<HealthService> logger;
public HealthService(ILogger<HealthService> logger)
{
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public async Task UpdateStatusInfo(string monitorId, HealthModel info)
{
if (info == null)
return;
HealthInfo[monitorId] = info;
await UpdateHealthState();
}
private async Task UpdateHealthState()
{
// Some enum mapping to get a global state
if (HealthInfo.Values.All(h => h.State == MonitorStates.ServiceOk))
State = HealthStates.Ok;
else if (HealthInfo.Values.Any(h => h.State == MonitorStates.ServiceWarning))
State = HealthStates.Warning;
else if (HealthInfo.Values.Any(h => h.State == MonitorStates.ServiceError))
State = HealthStates.Error;
else
State = HealthStates.Undefined;
// If the following line is uncommented, the component is rendered in Dutch,
// otherwise in the CurrentUICulture of the thread executing this method.
//Thread.CurrentThread.CurrentUICulture = new CultureInfo("nl");
if (StatusUpdated != null)
{
await StatusUpdated.Invoke(HealthInfo.Values.ToArray());
}
}
}
Концентратор SignalR
public class HealthHub : Hub<IMonitorClient>
{
private readonly HealthService healthService;
public HealthHub(HealthService healthService)
{
this.healthService = healthService ?? throw new ArgumentNullException(nameof(healthService));
}
public async Task ReceiveHealthInfo(HealthModel healthInfo)
{
await healthService.UpdateStatusInfo(Context.ConnectionId, healthInfo);
}
}