asp.netblazorsignalrdhtmldotnet-aspire

StateHasChanged not re-rendering DOM after SignalR callback


I am working on an application as part of a demo project of things I have learned over the years. This one combines Aspire Orchestration with a Blazor front. Sofar things have been a struggle learning and relearning things as I go. After some time I have figured out how to have my ApiService run a SignalR hub that will broadcast to clients on a specific web page a change to data. (I know Azure SignalR exists, but I don't know if this will end up hosted on azure for now)

However, after the data is acquired, the page DOM will not reload despite calling StateHasChanged.

Here is the code that matters:


<div id="mission-context" content="@mission">
    <h3>@mission.FileName: @mission.Name</h3>
    <div class="">
        <div>@mission.Description</div>
        <div>@mission.Loadout</div>
        <div>@mission.Guide</div>
        <div>@mission.Script</div>
    </div>
</div>

@code {
    MissionDto mission = new();

    protected override void OnInitialized()
    {
        HubConnection.On<MissionDto>("LiveUpdate", async newMission =>
        {            
            try
            {
                await InvokeAsync(() => UpdateMissionData(newMission));
            }
            catch (Exception ex)
            {
            }
        });
    }

    protected void UpdateMissionData(MissionDto newMission)
    {
        mission = newMission;
        StateHasChanged();
    }
}

If I slot in break points, they do get hit, but the client browser does not see a change. Did I miss something here?

If you need more code, the repository (including configuration and the orchestrator) is available here.


Solution

  • This is the standard Render Mode issue.

    You deployment site is set up for Per Page interactivity:

        <Routes />
    

    And I believe the page the code was pulled from is statically rendered:

    @page "/live"
    
    @attribute [StreamRendering(true)]
    

    A StreamRendering page is not a Blazor interactive page. Once the streaming is complete it's static.

    You need to review the main Microsoft documentation: https://learn.microsoft.com/en-us/aspnet/core/blazor/components/render-modes?view=aspnetcore-9.0

    Your simplest solution is to set Global Interactivity. See section - https://learn.microsoft.com/en-us/aspnet/core/blazor/components/render-modes?view=aspnetcore-9.0#apply-a-render-mode-to-the-entire-app