Azure SignalR Service with Asp.net Core/ Vue.js

Azure SignalR Service with Asp.net Core/ Vue.js

Realtime applications and use cases

Today's modern apps are expected to deliver up-to-date information without hitting a refresh button. Real-time apps require high frequency updates from the server. Examples are gaming, social networks, voting, auction, maps, GPS, dashboards and monitoring apps. Whiteboard apps and team meeting software are examples of collaborative apps.
Apps that require notifications. Social networks, email, chat, games, travel alerts, and many other apps use notifications.
Imagine you have a stock website and the stock prices are pushed to the screen constantly.
Flights which show you where your flight is in real time.
Look at my prezi slides

How Realtime applications work?

Polling: Client keep asking questions via HTTP requests

CLient keep asking questions from the server whether there is any update? Client send the Http request through Ajax and set the interval for peridoically asking same question. In Network tab client can see hundreds of HTTP request made which is obviously not a feature of a high performace website nor a real-time as it has some delays and not efficient either.

Long Polling: Client ask question with more persistence and less frequent HTTP requests

Another one is using Long Polling. In normal Http requests after client get back the response the connection will be closed. However in Long polling the connection stays open until there is an update from Server. After the response is retured to client with the update, after a specific timeframe the connection will be timeout. After that the Browser make another request and this process will happen recursively again and again. It is much better than Polling in terms of performance but still lots of requests should be invoked and the server should keep checking if any update is available while the connection is open.

Sent Server Event(SSE)

One way HTTP protocol based connection which only supports Text messages other than Binary ones. Only Server can push data and the use case is more for notification apps which does not require client interactions.

Web Socket

Websocket is persistent and bidirectional connection which takes the advantage of some Browser features and make a TCP connection with upgraded HTTP protocol called WS. It is the most efficient way of transport.
Web socket is supported by browesers which also support HTML5 since it is one of the HTML5 features. In order to wrok with Websocket you need to know socket programming. However, SignalR which is an open source library wrapps WebSocket and handles connection managements and all server-client communications out of the box.
WebSocket is a different protocol from HTTP. To establish a websocket connection an initial HTTP request will occur to the socket and ask for upgrading the handshake to WS. The it will stay alive till the socket is actively closed.

What technology SignalR uses under the hood?

SignalR handles connection management automatically, and lets you broadcast messages to all connected clients simultaneously. The connection between the client and server is persistent, unlike a classic HTTP connection, which is re-established for each communication. In order to get update from the server there are a few solutions to use.
SignalR is an open-source library for Asp.net/Asp.net Core that simplifies adding real-time functionality to web apps. It is wrapping up the real-time technologies based on the browsers capabilities.

Real-time web functionality is the ability to have server code pushes content to connected clients instantly instead of server waiting for a client to ask for new data.

SignalR automatically chooses the best transport method that is within the capabilities of the server and client.
SignalR will use HTML5 WebSocket API and will try to keep persistent full-duplex communication channel that operates through a single socket. If the browser does not support WebSocket, it will fallback to using another transport like Server Sent Events or Long Polling.
Behind the scenes, SignalR negotiates the best protocol to use for a specified connection based on what’s supported by both the server and the client. It then provides a consistent API for sending and receiving messages in real-time. Because it’s so easy to use, ASP.NET developers quickly adopted SignalR, making it the de facto stack for real-time ASP.NET development.

Hub is the heart of SignalR

The SignalR Hubs API enables you to call methods on connected clients from the server.
A hub is a high-level pipeline that allows a client and server to call methods on each other. In the server code, you define methods that are called by client. In the client code, you also define methods that are called from the server.
SignalR provides two built-in hub protocols: a text protocol based on JSON and a binary protocol based on MessagePack. MessagePack generally creates smaller messages compared to JSON since it is encoded. Older browsers must support XHR level 2 to provide MessagePack protocol support. (messages can be either Json or MessagePack format). Supporting binary data means other than text the video and images can also be transported.
SignalR creates a new instance of your Hub class each time it needs to handle a Hub operation such as when a client connects, disconnects, or makes a method call to the server.
Each time the server receives a method call from a client, a new instance of your Hub class processes the message. If you want to send messages to clients from your own code that runs outside the Hub class, you can't do it by instantiating a Hub class instance, but you can do it by getting a reference to the SignalR context object for your Hub class.
You need to introduce Hub to your client and server side apps in order to enable bi-communications.

Server Side code

Look at the Code here:
Edit chatsample
This is an Asp.net core Application which connects to the Azure SignalR Service and supports the CORS functionality for a client sitting in another domain. (A Vue.jS clientside application)

Client Side code

Look at the example client side code which is created by Vue.js App but potentially can be anything clientside including Javascript/Typescipt,... apps
The first step in introducing SignalR clientside library to your app:

npm install @aspnet/signalr-client
Edit vue-chat-client

SignalR and High traffic websites!

Asp.net/Core SignalR works perfectly as long as your site traffic is low but once it is hammered with loads of users it will have a few couple of issues.
We discussed that Websocket establishes a connection between client and server through TCP connections and keeps it open and full-duplex between them.
The number of concurrent TCP connections that a web server can support is limited.
In a high-traffic app that serves many clients, these persistent connections can cause servers to hit their maximum number of connections.Persistent connections also consume some additional memory, to track each connection.

If a server runs out of connections, you'll see random socket errors. In order to prevent this resource usage problem, you need to enable Scale out feature for your App.

Scale out servers

instances1
When the clients are getting more and more, your server needs to scale. Normaly applications has some ports to access and when they go idle the connection will be cut off however in SignalR since it is persistent connection, in a high-traffic app that serves many clients, these persistent connections can cause servers to hit their maximum number of connections.
Persistent connections also consume some additional memory, to track each connection
instances2
People normally keep the persistent connections to the same servers as the other web apps live. And the heavy use of connection-related resources by SignalR can brings overhead to the memory and cpu and makes the servers, scale out much quicker than other Http based applications. When SignalR opens and holds the last available TCP connections, other web apps on the same server also have no more connections available to them. It means you have to allocate a server for SignalR app separated from other web apps of your. That is not the only issue though.
Once the servers scale out, the new server should be aware of all clients otherwise it can not really broadcase messages to all connected clients.
So we need a backplane to propagate the connections information between different servers and keep the shared data between all instances. With Asp.net Core the best choice is Redis.
instances-redis

Redis backplane

To solve ths issue above you need to go through some efforts to config Redis backplane and trouble shooting possible issues around it, monitoring and pull the required code and libraries to your project.

The role of the backplane is just propagating the connections information between those servers so when a server wants to send a message to all clients, it sends to the backplane. The backplane knows all connected clients and which servers they're on. In asp.net/core the choice of backplan is Redis. Therefor you need to setup redis, config it and monitor it.

Sticky sessions

The second problem is for the SignalR to function approparetely each client should stay connected to the server which initiated the connection into them. So you need to config your load balancer in front of your server to include the sticky session or if you use azure app service you need to turn the session affinity.
In the normal HTTP connection, clients ask for a response from server and they don't expect same server will get back to them. Once cient gets back its response , next time it might connect to another server. However, in SignalR, once a client connects to a server it should stick to the same server.

SignalR is statefull which means the scaling of signalR servers is not that easy. To solve the issues and make life easier you can use Azure signalR service
But other than that you need to stick each client to the server they .

Cost of scaling out

The other problem is scale out is done based on the number of connected clients even if no message is sent or even if the client leaves the computer and teh connection open. A SignalR app uses significantly more connection resources than a web app without SignalR.
(/content/images/2019/03/redis-backplane.png)

Azur SignalR Service

While load balancing a large number of persistent WebSocket connections becomes a complicated problem to solve as you scale, Azure SignalR service can handle 99% of problems and increase performance, scalability and availability.
The Azure SignalR Service is a proxy rather than a backplane. Once client initiates a connection to the server, actually negotation to the server will be done first to see where client should be connected. The client is redirected to connect to the best Azure SignalR service.
Then it is Azure SignalR Service which talks to the App server when it needs any functionality or data, instead of client asking app server. For billing, only outbound messages from Azure SignalR Service are counted. Ping messages between clients and servers are ignored.
All persistent connections are offloaded to SignalR Service. App server only needs to handle the business logic in hub class, without worrying about client connections.
pricing and billing

Benefits

Client cannot directly connect to App servers anymore. They only do the negotation and redirected to the negotiated endpoint and stick to that Azure Service.
Client sends a negotiate request to the application server. With Azure SignalR Service SDK, application server returns a redirect response with SignalR Service's URL and access token. The application server receives an event with information from the new client. A logical connection to the client is created in the application server. The data channel is established from client to application server, via SignalR Service.SignalR service transmits data from the client to the pairing application server. And data from the application server will be sent to the mapped clients.See how internally works

  • Sticky sessions, also known as client affinity, is not required, because clients are immediately redirected to the Azure SignalR Service when they connect.
  • A SignalR app can scale out based on the number of messages sent, while the Azure SignalR Service automatically scales to handle any number of connections. For example, there could be thousands of clients, but if only a few messages per second are sent, the SignalR app won't need to scale out to multiple servers just to handle the connections themselves.
  • A SignalR app won't use significantly more connection resources than a web app without SignalR.
    The only way you can see the client is running against your Azure SignalR Service is by looing at console and network tab in the browser.Also you can see the metrics in azure portal with a bit delay

Step by Step Videos

In the videos below you can see a few topics including:

  • How to create the Azure SignalR Service?
  • How to publish your Asp.net core app to Azure App service?
  • How to add CORS to server side code to be able to talk to the client app on another domain when both are deployed to Azure App service.
  • End to End demo of the sample small real-time Bidding website

Serverless

Another reason may be you have no requirements to actually host a web application at all. The logic of your web application may leverage Serverless computing. For example, maybe your code is only hosted and executed on demand with Azure Functions triggers. This scenario can be tricky because your code only runs on-demand and doesn't maintain long connections with clients. Azure SignalR Service can handle this situation since the service already manages connections for you. See the my other post on Azure SignalR and Azure function for Serverless approach.

Troubleshooting and Tips

If you face any issue connecting to your Azure service backplane then look at this post of mine Azure signalr troubleshooting

Reference

CodeMeg
channel9
anthonychu
ASP
microsoft
HaoK
channel9
codementor
codementor-react
codingblast
pluralsightAzur SignalR Service
pricing