Список таблиц не обновляется внутри асинхронного таймера

Я новичок в Blazor, но не в объектно-ориентированных языках.

У меня есть веб-сервис с контроллером, который возвращает запросы из репозитория.

У меня есть независимая служба пользовательского интерфейса, которая вызывает веб-службу.

Я пытаюсь периодически обновлять таблицу с результатами, полученными от веб-сервиса.

@page "/"

@using System.Timers
@using WebServices 

@inject StatusService WebService // Has a httpClient to call web service
@inject IConfiguration Configuration

<h4>Status Viewer</h4> 

<table class = "table">
    <thead>
        <tr>
            <th>Name</th>
            <th>Status</th>
            <th>Last Update</th>
        </tr>
    </thead>
   
    <tbody>
        @if (StatusList != null)
        {
            @foreach (var status in StatusList)
            {
                <tr>
                    <td>@status.Name</td>
                    <td>@status.Status</td>
                    <td>@status.Timestamp</td>                   
                </tr>
            }
        }
    </tbody>
</table>

 
@code
{
    public IEnumerable<Status> StatusList { get; set; }

    private int UIReloadTime;
    private const int MINUTE_IN_MILLISECONDS = 60000;
    private System.Timers.Timer Timer { get; set; }

    protected override async Task OnInitializedAsync()
    {
        UIReloadTime = int.Parse(Configuration.GetValue<string>("ui:ReloadTime"));
        await UpdateStatus();

        Timer = new System.Timers.Timer();
        Timer.Interval = (UIReloadTime * MINUTE_IN_MILLISECONDS);
        Timer.Elapsed += OnElapsed;
        Timer.Enabled = true;
        Timer.Start();
    } 

    private async void OnElapsed(object? sender, ElapsedEventArgs e)
    {
        await UpdateStatus();
        await InvokeAsync(StateHasChanged);
    }

    private async Task UpdateStatus()
    {
        StatusList = await WebService.GetStatus();
    }
}

Я получаю допустимое значение во время процесса инициализации, но после этого ничего.

Я знаю, что это как-то связано с повторным рендерингом, но я не знаю, как его запустить, иначе я это делаю сейчас.

Я использую рендеринг на стороне сервера, но не уверен, пытаюсь ли я сделать что-то WASM с рендерингом на сервере.

Я пробовал PeriodicTimer, Threading.Timer и пробовал что-то уже около 2 дней, но ничего не работает.

Я также пытался реализовать IDisposable с типами таймера, но метод Dispose всегда вызывается.

Обновлено: С тех пор я также пытался создать новое приложение WASM и передавать его между попытками. Это все еще не работает. Я официально в тупике

EDIT_2: проблема вызывалась приложением, в котором для параметра «Местоположение интерактивности» было установлено значение для каждой страницы/компонента.

Я только что попробовал это в примере приложения, и оно сработало, как и ожидалось. Очевидно, у меня нет вашего веб-сервиса, поэтому я просто смоделировал обновление и добавил туда await Task.Delay(3000);, чтобы имитировать небольшую задержку при получении списка. Сначала я подумал, что может возникнуть проблема с вызовом await InvokeAsync(StateHasChanged) изнутри метода async void, но, похоже, это не проблема. Я тоже в недоумении, почему у тебя это не работает. Меня интересует одна вещь: как можно создать класс Status со свойством Status? Я не думаю, что компилятор это допустит.

Lex 24.07.2024 17:29

@Lex, лол, у меня снова работает. Я изменил часть кода, сделав его более общим, поскольку он предназначен для работы. Итак, в реальной настройке Status.Status отсутствует.

Beshman88 24.07.2024 17:40

@Lex Какой шаблон вы использовали при создании примера приложения?

Beshman88 24.07.2024 18:49

Я использую очень старый испытательный стенд, так было до того, как были выпущены различные интерактивные шаблоны. Просто стандартное приложение .Net 6 Blazor Server.

Lex 24.07.2024 21:55
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
58
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Шаблон: Веб-приложение Blazor — InteractiveServer — Global Interactivity

Я немного переработал ваш код, чтобы создать минимальный воспроизводимый пример. Я также перешел на использование System.Threading.Timer и TimeSpan для обозначения времени.

Мой объект данных и служба.

public record StatusData(string Name, string Status, DateTimeOffset Timestamp);

public class StatusService
{
    private List<StatusData> statusData = new List<StatusData>()
    {
        new("France", "Loaded", DateTimeOffset.Now.AddDays(-3)),
        new("Spain", "Loaded", DateTimeOffset.Now.AddDays(-2)),
        new("Portugal", "Loaded", DateTimeOffset.Now.AddDays(-1)),
    };

    public async ValueTask<IEnumerable<StatusData>> GetStatus()
    {
        // Fake an async API call
        statusData.Add(new("Me", "Loading", DateTimeOffset.Now));
        await Task.Yield();
        return statusData.AsEnumerable();
    }
}

И регистрация DI:

// Add services to the container.
builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents();

builder.Services.AddScoped<StatusService>();

var app = builder.Build();

И моя переформатированная страница:

@page "/"

@using System.Threading
@inject StatusService WebService
@implements IDisposable

<h4>Status Viewer</h4>

<table class = "table">
    <thead>
        <tr>
            <th>Name</th>
            <th>Status</th>
            <th>Last Update</th>
        </tr>
    </thead>

    <tbody>
        @if (StatusList != null)
        {
            @foreach (var status in StatusList)
            {
                <tr>
                    <td>@status.Name</td>
                    <td>@status.Status</td>
                    <td>@status.Timestamp</td>
                </tr>
            }
        }
    </tbody>
</table>


@code
{
    public IEnumerable<StatusData> StatusList { get; set; } = Enumerable.Empty<StatusData>();

    private TimeSpan _timeSpan = new TimeSpan(0, 0, 5);
    private Timer? _timer { get; set; }

    protected override async Task OnInitializedAsync()
    {
        await UpdateStatus();

        // Kick off the first one off timer
        _timer = new Timer(this.OnTimerElapsed, null, _timeSpan, Timeout.InfiniteTimeSpan);
    }

    private async void OnTimerElapsed(object? state)
    {
        await UpdateStatus();
        // Creates a new one off timer once we have the current data
        // prevents any thread and data conflicts
        _timer = new Timer(this.OnTimerElapsed, null, _timeSpan, Timeout.InfiniteTimeSpan);
        await InvokeAsync(StateHasChanged);
    }

    private async Task UpdateStatus()
    {
        StatusList = await WebService.GetStatus();
    }
    public void Dispose()
    {
        _timer?.Dispose();
    }
}

Репо GitHub временно здесь — https://github.com/ShaunCurtis/SO78788856

Я проверил его как есть, и он работает. Я понятия не имею, что на самом деле отличается, поскольку я уже многое из этого попробовал. Попробую это на работе и дам вам знать :)

Beshman88 24.07.2024 22:42

Вам необходимо предоставить минимально воспроизводимый пример неработающей версии. Проблема часто заключается в тех фрагментах кода, которые вы не показываете в вопросе [потому что не верите в их актуальность].

MrC aka Shaun Curtis 24.07.2024 22:46

Итак, это был глобальный интерактивный сервер, который исправил ситуацию. Мне пришлось создать новое приложение и применить все, что я сделал раньше, плюс пару изменений, которые вы внесли сюда, чтобы убедиться, что все настройки установлены правильно. Большое спасибо

Beshman88 24.07.2024 23:55

Поскольку вы не устанавливали режим рендеринга на странице, я предположил, что вы устанавливаете его глобально.

MrC aka Shaun Curtis 24.07.2024 23:58

Я новичок в Blazor, не совсем понял, как это работает. Теперь у меня гораздо больше ясности

Beshman88 24.07.2024 23:59

Другие вопросы по теме