Search code examples
c#asp.net-coreblazorblazor-client-side

Implementing Event Subscription with Blazor ClientSide Application


Our Blazor App is running on preview9.

I am trying to implement a .razor component that listens to an event from a NotificationService we have written to refresh the view whenever the service is invoked, but I seem to be missing something;

I have my service Interface (reduced for brevity);

public interface INotificationService
{
    event Action OnChange;
    Task<ServiceResponse<Notification>> AddNotificationAsync(Notification notification);
}

and in my implementation I invoke the OnChange event (again reduced for brevity);

public async Task<ServiceResponse<Notification>> AddNotificationAsync(Notification notification)
{
    /*...*/

    StateChanged();
}

Where StateChanged() is;

public event Action OnChange;

private void StateChanged() => OnChange?.Invoke();

In my Blazor.Client I resolved INotificationService in ConfigureServices as follows;

services.AddScoped<INotificationService, NotificationService>();

I then inject the service into the component I want to subscribe to the OnChange() event;

 @inject INotificationService NotificationService

 protected override async Task OnInitializedAsync()
 {
     NotificationService.OnChange += StateHasChanged;
 }

And then in my other razor page I again inject the same service and call the AddNotificationAsync method;

@inject INotificationService NotificationService

  await NotificationService.AddNotificationAsync(
                            new Notification { 
                                Level = NotificationLevel.Success, 
                                Text = $"Agreement Type with Id = {agreementType.Id} has been successfully added.".ToString()
                            });

However, calling t NotificationService.AddNotificationAsync is not triggering the OnChange and then the StateHasChanged of the component, as the component is not refreshing? Any ideas what I am doing wrong here please?


Solution

  • Following Microsoft docs Invoke component methods externally to update state, you should to change:

     @inject INotificationService NotificationService
    
     protected override async Task OnInitializedAsync()
     {
         NotificationService.OnChange += StateHasChanged;
     }
    

    By:

     @inject INotificationService NotificationService
    
     protected override async Task OnInitializedAsync()
     {
         NotificationService.OnChange += OnNotify;
     }
    
    
     public async Task OnNotify()
     {
        await InvokeAsync(() =>
        {
            StateHasChanged();
        });
     }
    

    In your code, you are invoking the component's StateHasChanged method outside of Blazor's SynchronizationContext.

    InvokeAsync is used to switch to the correct context and queue a render.