aspnet / SignalR

[Archived] Incredibly simple real-time web for ASP.NET Core. Project moved to https://github.com/aspnet/AspNetCore
Apache License 2.0
2.38k stars 446 forks source link

suggestion: multiple hubs per connection #955

Closed Jacknq closed 6 years ago

Jacknq commented 7 years ago

Critical feature if you dive your app and dont want everything (every method) in one hub. There is greater flexibility needed and anyone can put authorize attributes on methods or hubs that need to be authenticated, using one connection which can call any hub in endpoint. If you need to be more strict you typically make another endpoint where the authentication differs. Using alpha .net core version 1.0.0-alpha1

davidfowl commented 7 years ago

Critical feature if you dive your app and dont want everything (every method) in one hub.

Can you explain what this means?

There are currently not plans to support multiple hubs per connection.

Jacknq commented 7 years ago

sure, you can have an hub with a chat, but you can have a hub with methods getting some reports data and typically -, those two things dont belong together in code. So you create two separate hubs, and you want to access them with one authentication and one connection.

davidfowl commented 7 years ago

Why can't you put the same authentication on both hubs?

Jacknq commented 7 years ago

I can put same authorize attribute over them, but why do I need initiate two different connections on client connecting to same endpoint?

davidfowl commented 7 years ago

Because thats the new model. Let me flip the question, why do you have many hubs?

Jacknq commented 7 years ago

Because you separate logic into different classes that have nothing to do with each other, and you dont want to end at the end with ONE class containing all the methods - its hell in bigger scenarios. obvious reasons dont you think? they share only the endpoint, but you can remove some hub later..

davidfowl commented 7 years ago

Thanks for the feedback! No promises but it would be interesting to see how many hubs you have (it is 10? 5? 2?), see what they look like (in terms of number of methods and behavior) to help us understand the scenario better.

Also, it would be interesting to see what the client looks like. I'd like to see how different parts of the application wires up to the various hubs.

If indeed you need to use multiple hubs, instead of multiple hub proxies, you now have multiple connections, it's not as trivial but I'm not yet convinced it's a deal breaker. More data about how you're using it would definitely help.

Jacknq commented 7 years ago

Imagine big data (terabytes), big app scenario.. You can create something similar like webservice oriented scenario, where each hub is responsible for something. like typical scenario in my case I can Imagine 5-6 hubs, each responsible for another part of the system. Why would you ever combine classes and methods in one hub? Why coudnt you have one connection and access them all? I give you right oway two clients one is web browser another one is desktop app, it could be one and the same application written in react, vue.. and packed for different scenarios. Depending on permissions in that app for particular user, you use different hubs in backend. And yes if user has right for different modules in this app it ll use different hubs simultaneously... I can give you ton of examples that I see in everyday scenarios in field. just ask.

davidfowl commented 7 years ago

I can give you ton of examples that I see in everyday scenarios in field. just ask.

I'd like to see the typical code in these scenarios, preferably if we have existing signalr apps today that do this exact pattern it would be great to look at.

Jacknq commented 7 years ago

I cannot pass to you bigger apps from private companies. But you can have anlook at my simple example on github. or i can describe to you real world scenarios and why is good to have one connection with multiple hubs. What suprises me that thinking one connection and one hub will be always enough. no it wont you either want somethung flexible enough ot you go with other libraries like socket.io and so on.. and this now also possible to integrate and call from .net. be smart be flexible and create something that can do more than the others..

davidfowl commented 7 years ago

no it wont you either want somethung flexible enough ot you go with other libraries like socket.io and so on

Funny thing is socket.io isn't much different here, all you have are events so I'm not sure what you mean.

Thanks, I'll leave this bug open and let others chime in with their experiences.

Jacknq commented 7 years ago

Sorry, original Signalr 2 has this feature, even the one on .net 4.6, if I m not wrong its one big feature less! Same opinions here: https://stackoverflow.com/questions/19825901/how-to-have-multiple-signalr-hub-on-one-page here.. https://stackoverflow.com/questions/40277903/when-to-use-multiple-hubs-in-signalr , here.. https://stackoverflow.com/questions/19825901/how-to-have-multiple-signalr-hub-on-one-page here https://forums.asp.net/t/2005679.aspx?Multiple+instances+of+hub+does+it+make+sense+ Only argument I can think of why not to separate hubs is mobile battery consumption. Socket was just an example, there are more of them. Dont be just academic.

KPixel commented 7 years ago

@Jack85 I think the more important reason why there is one connection per hub is to keep things simple.

Sharing a connection across multiple hubs requires an internal routing solution as well as a much larger API surface (so that you can open the connection, and then pass it for each hub), and all that must be replicated in Javascript as well...

So, if it is an uncommon scenario, it makes sense to prioritize releasing a v1 of the current architecture. And maybe in the next version, this feature would be considered.

KPixel commented 7 years ago

Regarding the separation of concerns where you want hubs that handle very different services, a workaround can be to have one SignalR hub as the entry point where each method is a single line calling a separated class for that service.

Jacknq commented 7 years ago

Yes, but imagine those 1000 methods there, forced to do multiple inheritance, might be only elegant solution. I dont think it has to be complicated somehow authorize connection first and share this authentication with every hub call.

willthiswork89 commented 7 years ago

I did exactly as KPixel has pointed out. Separate your logic into multiple service layers as you would an MVC app. The separation of the business logic and database logic is achieved by injecting multiple service layers into the hub. From there the fact that you have a single hub means nothing. Since all its doing is taking the call and passing it straight down to the service layer.

RandyBuchholz commented 7 years ago

I can see a hub per domain running on one connection. For example, I have a Projects app. The project has some domains like "issues" and "benefits". This app is small and the domains aren't heavyweight enough to dedicate a whole sub-system. They're like micro-domains (I call them Scopes). They service different audiences - everyone gets issues pushed, and stakeholders get benefits pushed. Each Scope has a Front Controller to manage processes and full pages. There is a related Hub for each Scope to handle the chatty stuff in the pages.

Most of the time, these are accessed from the Project scope. A user is working on a project and needs to add an issue. It works either way, but it just feels better to have one connection talking to Project scope, and hitting the other hubs through that same connection.

granthoff1107 commented 6 years ago

@davidfowl, I'm still a bit new to Signalr so correct me if I'm wrong.
If you were to use this in an architecture similar to Microservices a hub per service. You could easily have over 100 hubs, For each hub you will have to manage the users? So for each user won't I be storing duplicate data 100 times? Or is there a way to the users of different hubs, while preventing memory from bloating?

stajs commented 6 years ago

Let me flip the question, why do you have many hubs?

I'll give our scenario. We have four independent software teams working on one module-based product, each team is responsible for their own modules. It sounds like it should be microservice'y, but we went monolith first. Coming from the old/current SignalR, we evolved to a state where each module had it's own hub, so teams could remain as independent as possible.

I don't particularly like where we've ended up. We've got eleven hubs so far with zero methods on them. We are just using them as a filter on the front end, so each module can just subscribe/process their own messages. I don't like that we have a connection per hub.

Judging from #1430 this is discouraged for new SignalR (we've just switched over to alpha2). The partial class suggestion is probably enough to maintain team independence for us.

Droppers commented 6 years ago

A solution given here is by creating services. This would mean I would need to pass the HubCallerContext to every method when needed, right?

analogrelay commented 6 years ago

We are just using them as a filter on the front end, so each module can just subscribe/process their own messages.

In that case, why not use a single Hub and add the clients to Groups as needed?

This would mean I would need to pass the HubCallerContext to every method when needed, right?

If you wanted to be able to call back to the client in one of your services, then yes. You could always build a base hub that sets up a wrapper to do this for you though.

stajs commented 6 years ago

In that case, why not use a single Hub and add the clients to Groups as needed?

I haven't investigated Groups in new SignalR yet, but my understanding of old SignalR they didn't seem to be a good fit for our use. With our Angular SPA and navigating between module "pages", we always want all SignalR messages to go down to all clients. There could be many Angular components on a "page" from different modules, so each component needs a way to filter out messages for its own module.

analogrelay commented 6 years ago

so each component needs a way to filter out messages for its own module

Yeah, this could be achieved with groups, but you'd need a separate connection for each module anyway, so it doesn't solve that problem. Is there a reason you can't do this filtering by using attributes in the messages themselves? Both Groups and Hubs have non-trivial server-side state requirements (memory is required to store state, both on the server and backplane, cpu is required to filter messages to the right connections). Tagging the messages on the server and having the client do the filtering/dispatching would move this logic from the server (where thousands of message streams have to be filtered and processed) to the client (where one message stream has to be filtered and processed). If all clients are receiving all messages, you don't really need the server to filter.

stajs commented 6 years ago

Is there a reason you can't do this filtering by using attributes in the messages themselves?

Nope! In fact this is something we will be moving towards soon, especially considering:

Both Groups and Hubs have non-trivial server-side state requirements...

TYVM for the extended explanation, I appreciate it. It definitely adds to the impetus for us.

aspnet-hello commented 6 years ago

We periodically close 'discussion' issues that have not been updated in a long period of time.

We apologize if this causes any inconvenience. We ask that if you are still encountering an issue, please log a new issue with updated information and we will investigate.