How to use shared SignalR Hub from different hosted project in ASP.NET Core 2.2
Asked Answered
O

2

5

I'm working with a project built with ASP.NET Core 2.2. The main solution contains multiple projects, which includes API, web and other class libraries.

We've used SignalR to displaying shared messages/notifications between the API project and the web project. For example, adding a new employee record from an API should call SignalR Hub and all the web client should received the notification.

Here is the current structure of our project

|- API
|- Hub_ClassLibrary
|- Services
|- Web

Flow:

Web > services > Hub 
API > services > Hub

Hub:

public class NotificationHub : Hub
{
    public async Task SendNotification(List<DocumentHistoryModel> notifications)
    {
        await Clients.All.SendAsync(Constants.ReceiveNotification, notifications);
    }
}

Web startup class:

app.UseSignalR(routes =>
{
    routes.MapHub<NotificationHub>("/notificationHub");
});

API startup class

app.UseSignalR(routes =>
{
    routes.MapHub<NotificationHub>("/notificationHub");
});

Service

private readonly IHubContext<NotificationHub> _hubContext;

public MyService(IHubContext<NotificationHub> hubContext)
{
    _hubContext = hubContext;
}

await _hubContext.Clients.All.SendAsync(ReceiveNotification, notifications);

The issue is, I can send and receive notifications from web, but from api call, web doesn't get any notification. I think problem is it creates two separate connections for each project, but then what is the best way to handle this kind of scenario?

Edit: I can get connection id and state "connected" in this api code, however, web is still not receiving any notification. Also tried connection.InvokeAsync

var connection = new HubConnectionBuilder()
     .WithUrl("https://localhost:44330/notificationhub")
     .Build();

connection.StartAsync().ContinueWith(task =>
{
    if (task.IsFaulted)
    {                    
    }
    else
    {                    
        connection.SendAsync("UpdateDashboardCount", "hello world");
    }
}).Wait();

enter image description here

Owenowena answered 21/1, 2020 at 11:23 Comment(12)
Are they sharing same host? Both Web and API?Wholly
Nope, host are different for both @WhollyOwenowena
host are different for both: So there will be two hubs? IMO it's better to have only one Hub: 1. Create a HubClient to push notifications to Hub? 1. Or as an alternative, use a sub/pub way like RabbitMQ/Redis sub/pub?Trifle
@itminus, So there will be two hubs? There is only one hub in a class library. But want to use in different project having same DB. Not sure about how to create such mechanism.Owenowena
@Div you can choose to use Azure SignalR so you can redirect to it in your both cases.Wholly
@Div I mean in your case there're two hub instances. One is used by Web and other other is used by API.Trifle
@Kiril1512, we aren't using Azure anywayOwenowena
@Div as @Trifle says you are using two different instances and so your clients have two separate connections. The best way to archive what do you want is have only one instance or using Redis to communicate with both of them.Wholly
@itminus, Yes, two hub instances is the issue. Is there any work around or best practice? I have thought to create a separate local web app that contains only hub. But don't think it's good solutionOwenowena
@Div Since in your scenario, there're at least two processes: Web+API. I think it's better to use a pub/sub way( e.g. RabitMQ/ Redis): there should be only one Hub, and a service subscribes some event, your Web & API can publish that type of event. And then the Hub will push notifications to clients. Or an easy way is (maybe not elegant) , replace the second hub with a HubClient, and push notification to Hub and then push notifications to other clientsTrifle
@itminus: Thanks! could you please share an example with .net core 2.2? It'd help me to understand easily. I have no idea how to use Redis with SignalROwenowena
@itminus, can't it achieve in this way?Owenowena
P
1

For this senario you are better off using pub/sub systems such as rabbitmq, kafka, akka.net, redis. However, if you insist on using signalr, the best solution would be to create a message coordinator with signalr and make it signalr host and then your other services would act as clients that sends their message to that signalr service and receive messages from that (you may even need to implement some logic for making your massage coordinator to queue messages and make them persistant) Besides, if you can migrate to asp.net core 3 you should definitally checkout grpc bi-directional streaming as well which can be a perfect solution to your problem.

Pronty answered 1/2, 2020 at 23:34 Comment(0)
C
0

you can inject your HubContext into your controller in API project and try hitting 'InvokeAsync'

Catchup answered 2/2, 2020 at 13:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.