Search code examples
c#asp.netblazorsignalr

ASP.NET Blazor Update the UI for a particular user using his ASPNerUserID


There is only 1 similar question in SO and it does not have any answer, only opinions and comments. Please study below image which more or less shows my question. Below the image, I explain further.

enter image description here

We have a multi project web application solution as above diagram. The UI is a ASP.NET 8.0 Blazor application. To send the UI update signals to the Presentation Project from the Logic Project, I send an event to the AZURE Event Grid (1) which is then successfully delivered to InterfaceUpdate Controller of the Presentation Project (2) and being parsed (3). Everything works fine up to this point.

Logic Project sends the ASPNetUserID (Its meaning detailed above in the image) of a particular User of the system so that only the UI elements of that particular user is being updated. This is the requirement. My question is, how do I use SignalR to update the UI element of that particular User by knowing his ASPNetUserID?

So if I wanted to create a code sample to answer this question, my scenario would be something like this;

  1. Create a ASP.NET 8.0 Blazor web application and integrate SignalR in the pipeline
  2. Create a InterfaceUpdate Controller that inherits from the ControllerBase decorated by [ApiController] and define a method that receives the payload of a webhook. The ASPNetUserID mentioned is being send by the Logic Project and could belong to anyone in the system.
  3. Create a page in the Blazor application and in the @code section, create a method called FinalMethod for example.
  4. When a webhook is received with the ASPNetUserID of a particular user, the FinalMethod is launched ONLY for that user and no other user who may or may not have logged in to the system.

Please note that I have this system Fully Functioning already in a ASP.NET MVC project! It has been working perfectly for years actually so I'm 100% certain that this is possible however, I cannot make it work in Blazor. In the MVC project, I inject my Hub as _hobContext in the webhook controller and in the webhook processor method, after I parse the JSON, I call "NotificationAdded" method which is a method in the Javascript file of the SignalR under the MVC.

await _hobContext.Clients.Users(webhookJson.ASPNetUserID).SendAsync("NotificationAdded");

But in Blazor, we don't have the Javascript so I don't know how to make it work now that our front end is Blazor.

I appreciate your time and effort in looking after this problem.


Solution

  • You need to collate the userId with the connectionId.

    Here I inject a service that is called during the hub OnConnectedAsync() to collate the userID with the connectionId.

    public class SignalHub(IClientOrchestrationService client) : Hub
    {
        private readonly IClientOrchestrationService client = client;
    
        public override async Task OnConnectedAsync()
        {
            await base.OnConnectedAsync();
            await client.OnConnectedAsync(Context);
        }
    }
    

    This service creates a db record with the user linked to a connection.

    public async ValueTask OnConnectedAsync(HubCallerContext context)
    {
        var hubConnection = new HubConnection
        {
            UserId = context.UserIdentifier,
            ConnectionId = context.ConnectionId,
            ConnectTime = dateTimeBroker.Now(),
        };
        await this.connectionService.AddConnectionAsync(hubConnection);
        ....
    }
    

    This code can be injected into a controller or another service on the server:

    builder.Services.AddScoped<IHubContextBroker, HubContextBroker>();
    
    public class HubContextBroker(IHubContext<SignalHub> hubContext) : IHubContextBroker
    {
        private readonly IHubContext<SignalHub> hubContext = hubContext;
    
        public async ValueTask JoinGroupAsync(string connectionId, string groupName)
            => await this.hubContext.Groups.AddToGroupAsync(connectionId, groupName);
        ....
    }
    

    This hubContext on the server can be used to send messages and assign users to groups etc.

    await hubContext.Clients.Group("somegroupname").SendAsync("SomeMessage");
    await hubContext.Clients.Client([connectionid]).SendAsync("SomeMessage");