ASP.NET API Controllers vs. SignalR Hub Methods - asp.net-core

I'm working on a prototype which uses SignalR for broadcasting messages from the server to clients. I also communicate from clients to the server. This is possible via 2 ways: via controllers or via a method call in the SignalR Hub.
Now my question:
Why would I choose either SignalR Hub Methods or the ASP.NET API Controllers as endpoints for client commands to call? (so not for events / broadcasting messages)
And to follow up: Is it recommended to use one or both?
I read that it's not recommended to call the Hub methods from the API Controllers, because they're for the clients to call, not for the server.
Both API Controller and SignalR Hub use HTTP.
I've used:
ASP.NET Core SignalR 1.1.0
Latest .NET Core version
And following link for SignalR information:
https://learn.microsoft.com/en-us/aspnet/core/signalr/introduction?view=aspnetcore-5.0

SignalR uses HTTP to establish connection with the hub (negotiation and handshake), then after connection established, it uses one of the following protocol: websockets, server sent events, long polling and forever frame. You can read more about it here.
You want to use SignalR to stream data to the client when it needs to be streamed. Most simple example would be refresh a status of something. Imagine you need to ask the server if the document was already loaded. You would call the endpoint n# of times until you get the desired answer. With the hub, the server will call the client via SignalR that the load was completed. As you can see you will save resources and drastically lower the amount of requests you make to the server.
So what you use? Hug or Controller? It really depends for the specific operation you want to do, not the general case of broadcast data.

Related

Designing REST API Domain Models for different clients in .NET Core

.NET API
If I am writing a domain model for a .NET API that will be used by a client e.g a mobile app, is it ok to use an automatically set entity property or a full prop?
For example so the client will be notified of the changes with an INotify property or I should just do that in the service layer of whatever client is using the API?
If you are writing a API, how could you notify the clients using INotify? A web-API (REST or SOAP) is, by definition, a distributed system. You can't notify your clients just using your server's C# classes. Your client could even be written in another language, like a ReactJS app, running somewhere around the globe.
Use a service layer to send notifications to your clients - you'll need to send a server-to-client message with SignalR, gRPC or another framework - and you can use the setter of the property to trigger this messages.

How can I send data to client-side after an API call when the caller is in another application

I have 2 web apps. One web app acts as a host (lets label as Host). All Web APIs resides here. Then the other web app calls those Web APIs (lets label as Client).
What I'm trying to accomplish is this:
Client calls a Web API using Jquery Ajax in Host and host processes this. After successful process, I want to be able to send some message in the HOST's client-side so I can update some UI.
That's the part I am unsure about. To notify the client-side of the Host so I can do some changes in UI, when the caller is in another app. I can't think of a way to pass some message so I can raise some popup, change some text, etc.
What I'm trying to accomplish is this: Client calls a Web API using Jquery Ajax in Host and host processes this. After successful process, I want to be able to send some message in the HOST's client-side so I can update some UI.
To achieve the requirement, you can try to integrate SignalR functionality into Apps.
Clients can connect to hub server, and clients can be added to two different groups, which provide a method for broadcasting messages to specified subsets of connected clients.
For more information about ASP.NET Core SignalR, you can check following docs:
https://learn.microsoft.com/en-us/aspnet/core/signalr/introduction?view=aspnetcore-3.1
https://learn.microsoft.com/en-us/aspnet/core/signalr/groups?view=aspnetcore-3.1#groups-in-signalr

Azure SignalR and Azure Web Application with multiple instances

We are developing ASP.Net core that is hosted as Azure Web Application.
We also use Azure SignalR service
Everything works great as long as we have single instance of the Web App, but once we scale it out we have the following problem:
From the Controller's action we resolve IHubContext and we send message to Hub's client. Everything works great so far
Hub's client accepts response and sends it TheHub endpoint.
The problem here is that response could be sent to another instance of Web App. So we send request from instance #1 but response is sent to instance #2 with 50% chance and instance #1 never receives response
Any ideas of how we could make it work so instance that emitted request actually received response?
SignalR has support for scaleout scenarios out of the box, it's called backplanes. The idea is that with help of one of backplane components, it will spread out SignalR events accross all instances. For Asp.Net framework, use one of these packages
Microsoft.AspNet.SignalR.ServiceBus3
Microsoft.AspNet.SignalR.ServiceBus
Microsoft.AspNet.SignalR.StackExchangeRedis
Microsoft.AspNet.SignalR.SqlServer
For ASP.Net Core only Redis is ported with Microsoft.AspNetCore.SignalR.StackExchangeRedis package, but there are some provided by community, see https://github.com/thomaslevesque/AspNetCore.SignalR.AzureServiceBus
public void ConfigureServices(IServiceCollection services)
{
services.AddSignalR()
.AddAzureSignalR(options =>
{
options.ApplicationName = "app1";
}
);
}
You could specify an ApplicationName in the server SDK for different server groups.
It will help your server generate access tokens like ......?hub=app1_<your_hub> during negotiation which can help our ASRS instances differentiate connections coming from different server groups
Unfortunately I didn't find reliable solution that wouldn't require a bit clumsy workarounds
But there are 2 solutions I could offer for this scenario
#LexLi suggested a good approach to solve this problem. So you basically can make your web app a SignalR client as well and make it a member of a group. This way every instance of web app is also a client and then instance that receives response for Hub's client can pass this response to group of web app instances
You could leverage Azure Service Bus topics. So once started instance will start subscribe to listen a topic. And then once any instance receives a response from Hub's client it would place response into Service Bus Topic and then every instance will receive this response from the topic
I was hoping that there could be a better solution for such problem

How to properly implement SignalR in a distributed, SOA environment?

I have a good understanding SignalR Hubs in a client/server scenario, where both the client and server are tightly coupled.
Let's say I have a WCF service that receives an update from some external resource. That service could update the database with a new value. However the client would need to be notified that an update has occurred. This could be handled through a service proxy that notifies the client (sounds a bit like polling) or some cache resource.
I could create C#-based clients and connect all the nodes via SignalR hubs, but this creates a closed, non-distributed system.
A SignaR hub that attaches to a WCF service could use the .Net 4.5 could implement a WCF asynchronous service operation, where a hub client would be notified with any service data changes.
I saw something similar in Push Notifications with NServiceBus and SignaR, but not sure if this is an optimal production-level solution.
What other methods could be used in this scenario and how would they be implemented?
If you are not using push notifications directly to the client or some kind of long polling then it is pretty typical to communicate with clients on another channel altogether. Not knowing the business case, it is hard to tell what would be feasible. Usually this manifests itself in the form of SMS, push notifications to mobile, email, etc. This does not answer your question directly, but you may find that there is another way to achieve your goal.

SignalR - Sending a Message from a WCF Project

I've followed the instructions from https://github.com/SignalR/SignalR/wiki/Hubs
entitled "Broadcasting over a Hub from outside of a Hub".
I got this method working from within an MVC Action in the same project. Requesting the Action sends the update to connected clients.
My problem is that I need to be able to send updates from another project, in particular a WCF Web Services project. My app has an API and a web component and when API users make calls that change things, these updates need to be pushed out to the Web clients via SignalR. And calling a web service with the same code as my Test Action doesn't work.
I also tried the same code inside an nunit unit test that didn't work either.
What do I need to do to make this same method described on the Wiki work for a WCF Project?
The easiest solution is probably to provide an API on your Web Application (use MVC or the new WebAPI) that broadcasts to all connected clients. Any other application (an NT Service, an NUnit test, ...) can call that API if it wants to send a message to the clients.
You can't expect SignalR to do anything if you aren't hosting a Hub either in a Web Application running under IIS, or another application hosting it directly.
If you need two-way communication from your separate application to your clients then simply make your application into a SignalR client too and have it communicate via the Web Application hosted SignalR to the clients and have it listen to messages from them too.
For example, here's how I have configured a complex Service + WebSite + Clients solution (ignore the purple for now):
The Live Web Server allows NT Services to connect and create SignalR Groups. NT Services send to those groups. Web browsers connect to a group and receive messages send to that group. In effect the middle box becomes a pubsubhub.
I cannot get exactly what you aim. But if I understood correctly you're trying to send some kind of notifications raised inside WCF services to SignalR clients.
If that's the case; I can suggest you my approach:
I have some WCF services and a SignalR hub in the same application server. IMHO, the best way to communicate WCF with SignalR hub is by using MSMQ.
When a notification occurs inside a WCF service, it puts the notification payload into MSMQ.
On the other end, SignalR hub listens the same queue. When a message put into the queue, it gets the content and broadcasts to the hub clients. Very easy and straightforward. No extra service/hub call at the server side.
SignalR hub can listen for new queue items by using System.Messaging.MessageQueue#ReceiveCompleted method. When this event raised, SignalR hub gets the queue item and broadcasts to its clients.