Practical ASP.NET Core SignalR: Scaling

In this section, I’m going to cover how to deal with scaling SignalR when in a server farm behind a load balancer.

ASP.NET Core SignalR Scaling

Typically to scale we would introduce a load balancer and additional instances of our application.

Introducing multiple instances of our application with SignlaR behind a load balancer is a problem because SignalR keeps track of connected clients in each instance.

This blog post is apart of a course that is a complete step-by-setup guide on how to build real-time web applications using ASP.NET Core SignalR. By the end of this course, you’ll be able to build real-world, scalable, production applications using the tools and techniques provided in this course.

If you haven’t already, check out the prior sections of this course.

  1. Course Overview
  2. ASP.NET Core SignalR Overview
  3. Basics
  4. Server Hubs
  5. HubContext
  6. Authorization

SignalR Scaling

The diagram below illustrates that we have 3 instances of our ASP.NET Core application behind a load balancer. When Client A makes a SignalR connection it is passed off to Instance #1. When Client B connects, it may get passed to Instance #2. Both instances are unaware of the other connected clients and there will be no communication between both.

Meaning, if you call Clients.All.SendAsync() from a Server Hub or HubContext, you will only be sending to the clients connected to that instance.

Redis

You can use Redis as a backplan which keeps information about all connected clients. SignalR uses the pub/sub feature to send messages to other servers. This solves the issue that if you call Clients.All.SendAsync() the message will be sent to all clients from all server.

If you’re using ASP.NET Core 2.2 or later the recommended package to use is: Microsoft.AspNetCore.SignalR.StackExchangeRedis which relies on StackExchangeRedis 2.x.

If you are using ASP.NET Core 2.1, you can use
Microsoft.AspNetCore.SignalR.Redis which relies on StackExchangeRedis 1.x.

Configuring

Depending on which package you are using you must call to add Redis to your AddSignalR() in your startups ConfigureServices()

You can also specify configuration options. In this example, I’m configuring the ClientName of the Redis connection.

To confirm my SignalR Hub is now using Redis, I’ll take a look at the connections in my Redis instance I’m hosting in a Docker container.

Sticky Sessions

There is one caveat when using a Redis backplane. If you are using anything other then WebSockets, meaning you are using Server-Sent Events or Long Polling, you must configure your load balancer to support sticky sessions. Sticky sessions are also known as client affinity and can be enabled in both Azure and AWS.

Get The Course!

You’ve got several options:

  1. Check out my Practical ASP.NET Core SignalR playlist on my CodeOpinion YouTube channel.
  2. Access the full course now by enrolling for free on Teachable.
  3. Follow along with the blog post series here on CodeOpinion.com
    1. Course Overview
    2. ASP.NET Core SignalR Overview
    3. Basics
    4. Server Hubs
    5. HubContext
    6. Authorization
    7. Scaling with Redis
    8. Scaling with Azure SignalR Service

Source Code

All of the source code for this blog post and this course is available the Practical.AspNetCore.SignalR repo on GitHub.

Roundup #35: Startup Hooks, HttpMaster, 7+M req/sec, Pre-Building Services, DockerComposeFixture

Here are the things that caught my eye this week in .NET.  I’d love to hear what you found most interesting this week.  Let me know in the comments or on Twitter.

[C#] Have some fun with .net core startup hooks

One feature of .net core 2.2 that didn’t catch my mind immediately is the startup hooks. Put simply, this is a way to register globally a method in an assembly that will be executed whenever a .net core application is started. This unlocks a whole range of scenarios, from injecting a profiler to tweaking a static context in a given environment.

Link: https://medium.com/@kevingosse/c-have-some-fun-with-net-core-startup-hooks-498b9ad001e1

HttpMaster 4.3

Link: https://www.httpmaster.net/download

ASP.NET Core: Saturating 10GbE at 7+ million request/s

Looking at the latest run from the TechEmpower Benchmarks continuous results ASP.NET 2.2 is the 3rd fastest webserver (0.046% off the top spot); able to respond to 7 Million HTTP request per second

Link: https://www.ageofascent.com/2019/02/04/asp-net-core-saturating-10gbe-at-7-million-requests-per-second/

Reducing initial request latency by pre-building services in a startup task in ASP.NET Core

This post follows on somewhat from my recent posts on running async startup tasks in ASP.NET Core. Rather than discuss a general approach to running startup tasks, this post discusses an example of a startup task that was suggested by Ruben Bartelink. It describes an interesting way to try to reduce the latencies seen by apps when they’ve just started, by pre-building all the singletons registered with the DI container.

Link: https://andrewlock.net/reducing-latency-by-pre-building-singletons-in-asp-net-core/

DockerComposeFixture

I happen to catch this twitter thread and noticed Khalid posted a link to this GitHub repo.

A XUnit fixture that allows you to spin up docker compose files and then run tests against them.

Link: https://github.com/devjoes/DockerComposeFixture

Enjoy this post? Subscribe!

Subscribe to our weekly Newsletter and stay tuned.

Practical ASP.NET Core SignalR: Authorization

HubContext

In this section, I’m going to cover how to configure your clients to send access tokens to an ASP.NET Core SignalR Hub for Authorization.

This blog post is apart of a course that is a complete step-by-setup guide on how to build real-time web applications using ASP.NET Core SignalR. By the end of this course, you’ll be able to build real-world, scalable, production applications using the tools and techniques provided in this course.

If you haven’t already, check out the prior sections of this course.

  1. Course Overview
  2. ASP.NET Core SignalR Overview
  3. Basics
  4. Server Hubs
  5. HubContext

Authorization

For the most part, everything works as expected when using Authrozation behind ASP.NET Core. Meaning, you can use the [Authorize] attribute on Server Hubs just like you would on Controllers.

However, if you are using WebSockets as the transport and are using access tokens, then there is a bit of configuration required.

Client Configuration

In the signalR.HubconnectionBuilder().withUrl() allows us to specify an options object that has a property called accessTokenFactory which is a function needs to return the access token.

Where “MyTokenGoesHere” is a string, you would likely be using a means to return the access token you send with all of your other HTTP calls from the rest of your frontend application.

Query String

When the browser/client connects to the hub, it will add a query string parameter called “access_token“. The value will be what is returned from the accessTokenFactory.

ws://domain/messages?id=XXX&access_token=MyTokenGoesHere

Authorization Header

The reason for the SignalR client library for using the Query String to send the access token is that web sockets do not support the Authorization header. You can read more about this over at this GitHub issue.

Setting Token

Now that the access token is being sent via the query string, we need to configure out authentication in the Startup.cs to look for it in the query string and set it on the HttpContext.Token so that our authorization can use it as if it were coming from the Authorization header.

To do this with JWT, we can specify Events option and implement the OnMessageReceived property which is an Action<HttpContext>

We will implement this to look for the access_token in the query string, and if it exists, set it to the Httpcontext.Token

Get The Course!

You’ve got several options:

  1. Check out my Practical ASP.NET Core SignalR playlist on my CodeOpinion YouTube channel.
  2. Access the full course now by enrolling for free on Teachable.
  3. Follow along with the blog post series here on CodeOpinion.com
    1. Course Overview
    2. ASP.NET Core SignalR Overview
    3. Basics
    4. Server Hubs
    5. HubContext
    6. Authorization
    7. Scaling with Redis
    8. Scaling with Azure SignalR Service

Source Code

All of the source code for this blog post and this course is available the Practical.AspNetCore.SignalR repo on GitHub.