Open Closed

How to Display Real-Time Notifications with SignalR in Blazor Web App When Using Distributed Event Bus (RabbitMQ) #8022


User avatar
0
thanhlg created
  • ABP Framework version: v8.3.0
  • UI Type: Blazor Web App
  • Database System: EF Core (PostgreSQL)

Hi Support Team,

I'm using the Module Template and Application Template (Blazor Web App).

I'm using the Distributed Event Bus with RabbitMQ to send communication between the IN and GL modules. Afterward, I build the IN and GL modules into packages and install them into the Main (Blazor Web App).

Currently, I want to integrate SignalR to receive notifications when the event bus processing is completed and display a notification on the user interface to indicate that the processing is done. I need the notification (https://abp.io/docs/latest/framework/ui/blazor/notification) to appear on the user's screen, regardless of which screen they are currently viewing, not just on the screen where the event was initiated.

For example, if the event is triggered on screen A, but while it is processing I navigate to screen B, I want the notification to show up on screen B if it is completed at that time. How should I do it?

I look forward to your response. Thanks!


11 Answer(s)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    You can consider adding a component to the layout/global page to use Singalr. in this way, you can globally listen to the event and show some notifications.

    https://abp.io/docs/latest/framework/ui/blazor/layout-hooks

  • User Avatar
    0
    thanhlg created

    hi

    You can consider adding a component to the layout/global page to use Singalr. in this way, you can globally listen to the event and show some notifications.

    https://abp.io/docs/latest/framework/ui/blazor/layout-hooks

    Can you please give an example of this, with a return notification using SignalR and Distributed event bus?

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    You can refer to https://abp.io/docs/latest/framework/ui/blazor/layout-hooks to add a component.

    Then, connect the Singlar hub and add event listen in it. https://learn.microsoft.com/en-us/aspnet/core/blazor/tutorials/signalr-blazor?view=aspnetcore-8.0&tabs=visual-studio

  • User Avatar
    0
    thanhlg created

    Hi, I did it this way and I was able to receive notifications through SignalR. However, I encountered another issue when using the event bus to send events and handle SignalR when receiving to return notifications. Below is my code:

    I want to send notifications only to the user who triggered the event instead of sending them to everyone. I have referred to the documentation here and followed the guidelines, but I'm not receiving any return notifications from SignalR anymore. Currently, CurrentUser is returning null.

    What did I do wrong?

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    You can add a service to store the current user id and connection id.

    Maintain the dictionary in OnConnectedAsync/OnDisconnectedAsync, then get connection id by user id(GetConnectionIdsByKey)

    public class QaUiConnectionStore : ISingletonDependency
    {
        private readonly Dictionary<string, HashSet<string>> _connections = new();
        
        public void AddConnection(string key, string connectionId)
        {
            lock (_connections)
            {
                if (!_connections.ContainsKey(key))
                {
                    _connections.Add(key, new HashSet<string>());    
                }
    
                lock (_connections[key])
                {
                    _connections[key].Add(connectionId);
                }
            }
        }
    
        public IEnumerable<string> GetConnectionIdsByKey(string key)
        {
            if (_connections.TryGetValue(key, out var connection))
            {
                return connection;
            }
    
            return Enumerable.Empty<string>();
        }
    
        public void RemoveConnection(string key, string connectionId)
        {
            lock (_connections)
            {
                if (!_connections.TryGetValue(key, out var connection))
                {
                    return;
                }
    
                lock (connection)
                {
                    connection.Remove(connectionId);
                    if (connection.Count == 0)
                    {
                        _connections.Remove(key);
                    }
                }
            }
        }
    }
    
    public class QaUiNotificationHub : AbpHub<IQaUiNotificationClient>
    {
        private readonly QaUiConnectionStore _qaUiConnectionStore;
    
        public QaUiNotificationHub(QaUiConnectionStore qaUiConnectionStore)
        {
            _qaUiConnectionStore = qaUiConnectionStore;
        }
    
        public override Task OnConnectedAsync()
        {
            if (IsUserAuthenticated())
            {
                var key = CurrentUser.Id.ToString();
                _qaUiConnectionStore.AddConnection(key, connectionId: Context.ConnectionId);
            }
            
            return base.OnConnectedAsync();
        }
    
        public override Task OnDisconnectedAsync(Exception? exception)
        {
            if (IsUserAuthenticated())
            {
                var key = CurrentUser.Id.ToString();
                _qaUiConnectionStore.RemoveConnection(key, connectionId: Context.ConnectionId);
            }
            
            return base.OnDisconnectedAsync(exception);
        }
    
        private bool IsUserAuthenticated()
        {
            return CurrentUser.IsAuthenticated && CurrentUser.Id.HasValue;
        }
    }
    
    
  • User Avatar
    0
    thanhlg created

    Could you please check if I'm doing this correctly? It's still not working. :(. Do I need to configure anything else?

    Application:

    Application.Contracts:

    HttpApi:

    Blazor.Client/Components:

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Can you try to get the user from QaUiConnectionStore.GetConnectionIdsByKey(eventData.UserId.ToString())?

    Inject QaUiConnectionStore service and call GetConnectionIdsByKey

  • User Avatar
    0
    thanhlg created

    hi

    Can you try to get the user from QaUiConnectionStore.GetConnectionIdsByKey(eventData.UserId.ToString())?

    Inject QaUiConnectionStore service and call GetConnectionIdsByKey

    Sorry for the late reply. This approach still isn’t working. Today, I tried debugging in the IN Module (Module Template), and I was able to get event.UserId. But after building the IN Module into a package and installing it in the Main app (Blazor Web App), eventData.UserId comes back as null when I run the event

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Do you mean the user id is null here?

    Please share full code of this class.

    Thanks

  • User Avatar
    0
    thanhlg created

    I have resolved the issue in another way. Thank you for your support.🌻

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    👍

Made with ❤️ on ABP v9.1.0-preview. Updated on November 11, 2024, 11:11