Search code examples
events.net-coreservice-workerblazor

Blazor: Event sent from Service to Component is null


I have program composed of Blazor component and Worker Service. I'm using .NET CORE 3.1

I've based my code on manual to Blazor components

At my worker service's side I have:

    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);
        }
    }

In my Blazor Component:

@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;
    }
}

After debugging I notified, that Notify event is properly wired in Blazor component, in OnInitialized() method (I've tried also the version with OnInitializedAsync() ) however, every time, when service calls Update() method, during the condition check: if (Notify != null), the Notify is null.

I can't find the reason. Thank you for any suggestions !


Solution

  • 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;
        }
    }
    

    In the Startup.cs:

    services.AddHostedService<MyService>();
    services.AddSingleton<InjectableService>();