Blazor: событие, отправленное из службы в компонент, равно нулю - PullRequest
1 голос
/ 22 января 2020

У меня есть программа, состоящая из компонента Blazor и Worker Service. Я использую. NET CORE 3.1

Мой код руководства основан на компонентах Blazor

На стороне моей рабочей службы у меня есть:

    public event Func<double, Task> Notify;
    public double Data{ get; set; }

    public async Task Update(double data)
    {
        if (Notify != null)
        {
            await Notify.Invoke(data).ConfigureAwait(false);
        }
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
             await Update(Data).ConfigureAwait(false);
             ...

             await Task.Delay(1000, stoppingToken).ConfigureAwait(false);
        }
    }

В моем компоненте Blazor:

@using MyNamespace
@inject WorkerService MyService
@implements IDisposable

<div>@DataToDisplay</div>

@code {

    private double DataToDisplay{ get; set; }

    protected override void OnInitialized()
    {
        MyService.Notify += OnNotify;
    }

    public async Task OnNotify(double data)
    {
        await InvokeAsync(() =>
        {
            DataToDisplay= data;
            StateHasChanged();
        });
    }

    public void Dispose()
    {
        MyService.Notify -= OnNotify;
    }
}

После отладки я уведомил, что событие Notify правильно подключено в компоненте Blazor, в методе OnInitialized () (я пробовал также версию с OnInitializedAsync()) однако каждый раз, когда служба вызывает метод Update(), во время проверки условия: if (Notify != null), Notify является нулевым.

Я не могу найти причину. Спасибо за любые предложения!

Ответы [ 3 ]

2 голосов
/ 23 января 2020
public class InjectableService
    {
        public double Value { get; set; }
        public event Func<Task> Notify;
        public double Data { get; set; }

        public  async Task RefreshAsync(double value)
        {
            if (Notify is { })
            {
                Value = value;
                await Notify.Invoke();
            }
        }
public class MyService : BackgroundService
    {
        private readonly InjectableService _injectableService;

        public MyService(InjectableService injectableService)
        {
            _injectableService = injectableService;
        }

        public async Task Update(double value)
        {
            await _injectableService.RefreshAsync(value);
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                await Update(_injectableService.Value + 0.1).ConfigureAwait(false);
                await Task.Delay(1000).ConfigureAwait(false);
            }
        }
    }
@inject InjectableService MyService
@implements IDisposable

<p>@MyService.Value</p>

@code {
    protected override void OnInitialized()
    {
        MyService.Notify += OnNotify;
    }

    public async Task OnNotify()
    {
        await InvokeAsync(() =>
        {
            StateHasChanged();
        });
    }

    public void Dispose()
    {
        MyService.Notify -= OnNotify;
    }
}

В файле автозагрузки:

services.AddHostedService<MyService>();
services.AddSingleton<InjectableService>();
1 голос
/ 24 января 2020

Основываясь на обсуждении на github: https://github.com/dotnet/extensions/issues/553 У меня есть, что HostedServices являются переходными с тех пор. NET Core 2.1.

Однако есть возможность использовать его как API, что описано в нижней части этого потока:

в Startup.cs, в ConfigureServices(IServiceCollection services):

services.AddSingleton<BackgroundWorkerService>();
services.AddSingleton<IHostedService>(p => p.GetService<BackgroundWorkerService>());

И это, очевидно, работает как шарм.

0 голосов
/ 25 марта 2020

Я столкнулся с такой же проблемой, как ваша, так как я хотел обновить некоторые элементы в пользовательском интерфейсе, используя событие.

Изучая методы регистрации службы из официальных документов Microsoft здесь , services.AddSingleton<IMyDep, MyDep>(); был путь к go, поскольку он допускал несколько реализаций.

Все, что мне нужно было сделать, это создать класс с интерфейсом:

public interface INotifierService
{
    // In an Interface, its all Public!


    delegate void UiChangedEventHandler(object source, EventArgs args);

    event UiChangedEventHandler UiChanged; //Handler


}

и другой класс, производный от этого интерфейса:

public class NotifierService:INotifierService
{

    public event INotifierService.UiChangedEventHandler UiChanged; //Event from the base Interface

    protected virtual void OnUiChanged()
    {
        UiChanged?.Invoke(this, EventArgs.Empty);
    }

}

и зарегистрируйте их в Startup.cs:

        services.AddSingleton<Services.INotifierService, Services.NotifierService>();

, и это сработало!

Конечно, не забудьте добавить интерфейс в ваш файл .razor и подписаться на его событие!

...