connectionsignalrmessageblazor-server-sidesend

Call SignalR from Blazor Server Side


I have a Blazor app written in .NET6 which implements SignalR.

Here is an example of SignalR Hub in server side:

[HubName("ThreadHub")]
public class ThreadHub : Hub
{
    public async Task SendMessage(Threading_Pair threading_Pair)
    {
        await Clients.All.SendAsync("ReceiveMessage", threading_Pair);
    }
}

Here is an example of maphub in program.cs in server side:

app.MapHub<ThreadHub>("/threadhub");

Here is an example of SignalR initialization on razor component in client side:

private HubConnection? hubConnection;

private IList<string> messages = new List<string>();

protected override async Task OnInitializedAsync()
{
    // Init Broadcast service with SignalR
    hubConnection = new HubConnectionBuilder()
        .WithUrl(navigationManager.ToAbsoluteUri("/threadhub"))
        .Build();

    hubConnection.On<string, string> ("ReceiveMessage", (id, message) => {
        var encodedMsg = $"{id}: {message}";
        messages.Add(encodedMsg);
        StateHasChanged();
    });

    await hubConnection.StartAsync();
}

Here is an example of SignalR function to send message on razor component in client side:

if (hubConnection is not null)
{
    if (hubConnection.State == HubConnectionState.Connected)
    {
        await hubConnection.SendAsync("SendMessage", "Admin", "Hellow to all users! Starting the heavy job!");
    }
}

The application now is working fine between client and server and can send and retrieve messages across all open windows.

The question is how the application itself can send messages from server side? For example this application is generating some threads and i want to know start and stop of their process. In this case the call will happen from the server side, so how i can efficiently sent message from server?

So far the only though is to open a hubConnection like in the razor component in client side"

hubConnection = new HubConnectionBuilder()
            .WithUrl(navigationManager.ToAbsoluteUri("/threadhub"))
            .Build();

In the above example the navigationManager.ToAbsoluteUri() translates for my my running url application in the client and adds the "/threadhub" but in this case, I do not have the Navigation manager to get the url of the application, any ideas?


Solution

  • After a lot of investigation on this topic, to make a more elegant solution I concluded on the following:

    On the Client Project Startup, we can store the Environment Address into static variables on the Shared Project which can be referenced form Server Project:

    public void ConfigureServices(WebAssemblyHostBuilder builder)
    {
        string? app_env = builder.HostEnvironment.Environment;
        Parameters.enviroment = app_env;
        string? app_url = builder.HostEnvironment.BaseAddress;
        Parameters.urlstring = app_url;
    }
    

    Although, one thing here is that the Server Project Starts before the client project and therefore if any SingalR functions runs on the startup it may has not the variable set if the Client isn't startup yet. This will make unnecessary the need to have hardcoded the application host/url.