June 3rd, 2019

What’s new in Azure SignalR 1.1.0 Preview 1

Ken Chen
Principal Software Engineering Manager

We just shipped 1.1.0 Preview 1 of Azure SignalR Service SDK to support some new features in ASP.NET Core 3.0, including endpoint routing and server-side Blazor. Let’s take a look how you can use them in your Azure SignalR application.

Here is the list of what’s new in this release:

  • Endpoint routing support for ASP.NET Core 3
  • Use SignalR service in server-side Blazor apps
  • Server stickiness

Endpoint routing support for ASP.NET Core 3

For those who are using Azure SignalR, you should be familiar with AddAzureSignalR() and UseAzureSignalR(). These two methods are required if you want to switch your app server from self-hosted SignalR to use Azure SignalR.

A typical Azure SignalR application usually looks like this in Startup.cs (note where AddAzureSignalR() and UseAzureSignalR() are used):

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddSignalR()
            .AddAzureSignalR();
    ...
}

public void Configure(IApplicationBuilder app)
{
    ...
    app.UseAzureSignalR(routes => 
    { 
        routes.MapHub<Chat>("/chat"); 
    });
    ...
}

ASP.NET Core 3.0 introduced a new endpoint routing support which allows routable things like MVC and SignalR to be mixed together in a unified UseEndpoints() interface.

For example, you can call MapGet() and MapHub() in a single UseEndpoints() call, like this:

app.UseEndpoints(routes =>
{
    routes.MapGet("/foo", async context => {
        await context.Response.WriteAsync("bar");
    });
    routes.MapHub<Chat>("/chat");
});

This new syntax is also supported in the latest Azure SignalR SDK so you don’t need to use a separate UseAzureSignalR() to map hubs.

Now your Azure SignalR application looks like this:

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddSignalR()
            .AddAzureSignalR();
    ...
}

public void Configure(IApplicationBuilder app)
{
    ...
    app.UseRouting();
    app.UseEndpoints(routes =>
    {
        routes.MapHub<Chat>("/chat");
    });
    ...
}

The only change you need to make is to call AddAzureSignalR() after AddSignalR().

This will be very useful in the case that SignalR is deeply integrated in your code base or the library you’re using. For example, when you’re using server-side Blazor.

Use SignalR service in server-side Blazor apps

Server-side Blazor is a new way to build interactive client-side web UI in ASP.NET Core 3. In server-side Blazor, UI updates are rendered at server side, then sent to browser through a SignalR connection. Since it uses SignalR, there is a natural need to use Azure SignalR service to handle the SignalR traffic so your application can easily scale.

blazor

If you look at some server-side Blazor code samples, you’ll see they have a call to MapBlazorHub() to setup the communication channel between client and server.

app.UseEndpoints(endpoints =>
{
    ...
    endpoints.MapBlazorHub();
    ...
});

The implementation of this method calls MapHub() to create a SignalR hub at server side. Before this release there is no way to change the implementation of MapBlazorHub() to use SignalR service. Now if you call AddAzureSignalR(), MapBlazorHub() will also use SignalR service to host the hub instead of hosting it on the server.

Please follow these steps to change your server-side Blazor app to use SignalR service:

  1. Open your Startup.cs, add services.AddSignalR().AddAzureSignalR() in ConfigureServices().
  2. Create a new SignalR service instance.
  3. Get connection string and set it to environment variable Azure:SignalR:ConnectionString.

Then run your app you’ll see the WebSocket connection is going through SignalR service.

Check out this repo for a complete code sample.

Server stickiness

The typical connection flow when using SignalR service is that client first negotiates with app server to get the url of SignalR service, then service routes client to app server.

When you have multiple app servers, there is no guarantee that two servers (the one who does negotiation and the one who gets the hub invocation) will be the same one.

We hear a lot of customers asking about whether it’s possible to make the two servers the same one so they can share some states between negotiation and hub invocation. In this release we have added a new “server sticky mode” to support this scenario.

To enable this, you just need to set ServerStickyMode to Required in AddAzureSignalR():

services.AddSignalR().AddAzureSignalR(options => {
    options.ServerStickyMode = ServerStickyMode.Required;
});

Now for any connection, SignalR service will guarantee negotiation and hub invocation go to the same app server (called “server sticky”).

This feature is very useful when you have client state information maintained locally on the app server. For example, when using server-side Blazor, UI state is maintained at server side so you want all client requests go to the same server including the SignalR connection. So you need to set server sticky mode to Required when using server-side Blazor together with SignalR service.

Please note in this mode, there may be additional cost for the service to route connection to the right app server. So there may be some negative impact in message latency. If you don’t want the performance penalty, there is another Preferred mode you can use. In this mode stickiness is not always guaranteed (only when there is no additional cost to do the routing). But you can still gain some performance benefits as message delivery is more efficient if sender and receiver are on the same app server. Also when sticky mode is enabled, service won’t balance connections between app servers (by default SignalR service balances the traffic by routing to a server with least connections). So we recommend to set sticky mode to Disabled (this is also the default value) and only enable it when there is a need.

You can refer to this doc for more details about server sticky mode.

Author

Ken Chen
Principal Software Engineering Manager

Ken Chen is the engineering manager of Azure SignalR service team at Microsoft.

5 comments

Discussion is closed. Login to edit/delete existing comments.

  • Tomislav Markovski

    Great addition! Works well.
    The latest version of the Microsoft.Azure.SignalR --version 1.1.0-preview1-10442 however throws an exception for missing HubConnectionContextOptions at runtime.

  • Coleten McGuire

    Anyone else running into this issue?
    Uncaught Error: Server returned handshake error: Protocol not supported by Azure SignalR Service: blazorpack

    • Jialin XinMicrosoft employee

      Hi Coleten, thanks for have a try! The exception occurs because no server connection available when client tries to connect to service and the service falls back to serverless mode which requires service to understand the new blazorpack protocol. You may check app server logs to take a look why server connection is down and make sure client connects with server connection available.

  • Dmitry Pavlov

    Wow, this is really awesome! Are there plans to make SignalR sitting in API container easily configurable and available to connect from client side UI app container? Like for pods in Kubernetes environment, or just Docker containers.

    • Ken ChenMicrosoft employee Author

      SignalR already can run inside container. Just dockerize your self-hosted or Azure SignalR app like a normal .NET core app then you can run it in Docker or Kubernetes.