Real-time with ASP.NET SignalR and Azure Mobile .NET Backend

We just released an update for Azure Mobile Services .NET backend which enables you to use ASP.NET SignalR for real-time, bi-directional communications with your mobile applications. SignalR will use WebSockets under the covers when it's available, and fallback to other “techniques” (i.e. HTTP hacks ;) when it isn't. Regardless of the mode, your application code stays the same.

The integration with Azure Mobile Services includes:

  • Unified Authentication: Protect your SignalR Hubs the same way you protect any of your Mobile Service Web API controllers using a simple AuthorizeLevel attribute.
  • Dependency Injection: SignalR Hubs are integrated with Autofac so that they can get instantiated with whatever dependencies they need.
  • Web API Integration: Send messages to your connected SignalR applications from any Web Api controller or scheduled job – we automatically give you access to SignalR Hubs from the ApiServices context.
  • Automatic Scale-out: When scaling out your Azure Mobile Service using multiple front-ends we automatically scale out SignalR using Azure Service Bus as the backplane for sync’ing between the front-ends.

If you are not familiar with ASP.NET SignalR then there’s a bunch of great tutorials available and if you are new to Azure Mobile Services then there’s a good introduction in Scott Guthrie’s blog.

Ok, enough with the intro, let’s get started…

Getting the Latest Bits

You can either start from a Visual Studio Azure Mobile Service project template or you can start using a Quick Start project downloaded from your already created Azure Mobile Service (using the Azure Portal). For simplicity, we here use the Quick Start project with an associated Windows Store client App. First you need to update the following NuGet references in your Azure Mobile .NET backend Visual Studio project to point to the latest release (1.0.295):

  1. WindowsAzure.MobileServices.Backend
  2. WindowsAzure.MobileServices.Backend.Tables
  3. WindowsAzure.MobileServices.Backend.Entity 

It should look like this:

UpdateNugets

Second, you need to add a reference to the WindowsAzure.MobileServices.Backend.SignalR NuGet package:

SignalRNuget

Creating a Simple SignalR Hub

ASP.NET SignalR is an optional extension to Azure Mobile Services that only is loaded if you ask it to, so the first thing to do is to add this line to your WebApiConfig.Register method (see line 6 -- the rest of that methods stays the same):

    1: public static class WebApiConfig
    2: {
    3:     public static void Register()
    4:     {
    5:         // Initialize SignalR
    6:         SignalRExtensionConfig.Initialize();
    7:  
    8:         ...
    9:  
   10:     }
   11: }

Next, add a Hub class to your project that looks like this:

    1: public class ChatHub : Hub
    2: {
    3:     public ApiServices Services { get; set; }
    4:  
    5:     public string Send(string message)
    6:     {
    7:         return "Hello from SignalR Chat Hub!";
    8:     }
    9: }

Note that we automatically inject the ApiServices class giving you access to a bunch of other Mobile Service features. You can of course also add your own dependencies (see Autofac and Azure Mobile Services .NET Backend).

This is all your need for the first round of the server code so compile and deploy your service to Azure directly from Visual Studio by right-clicking on the service project and select Publish. Then pick a mobile service and publish it. It should look like this:

Publish

Adding Client Support

In this scenario we use the Windows Store App from the Quick Start project but you can use any of the platforms supported by Azure Mobile Services including iOS, Android, Windows Phone, etc.

Start by installing the Microsoft ASP.NET SignalR .NET Client NuGet package into your client project. Then in the MainPage.xaml.cs file, add a method to the MainPage class looking like this (line 15 onwards is just to support the sample):

    1: private async Task ConnectToSignalR()
    2: {
    3:     hubConnection = new HubConnection(App.MobileService.ApplicationUri.AbsoluteUri);
    4:     if (user != null)
    5:     {
    6:         hubConnection.Headers["x-zumo-auth"] = user.MobileServiceAuthenticationToken;
    7:     }
    8:     else
    9:     {
   10:         hubConnection.Headers["x-zumo-application"] = App.MobileService.ApplicationKey;
   11:     }
   12:     IHubProxy proxy = hubConnection.CreateHubProxy("ChatHub");
   13:     await hubConnection.Start();
   14:  
   15:     string result = await proxy.Invoke<string>("Send", "Hello World!");
   16:     var invokeDialog = new MessageDialog(result);
   17:     await invokeDialog.ShowAsync();
   18:  
   19:     proxy.On<string>("hello", async msg =>
   20:     {
   21:         await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
   22:         {
   23:             var callbackDialog = new MessageDialog(msg);
   24:             callbackDialog.Commands.Add(new UICommand("OK"));
   25:             await callbackDialog.ShowAsync();
   26:         });
   27:     });
   28: }

Note that you can either be logged in with the Application Key (the default) or as a specific User using one of the authentication providers supported by Azure Mobile Services (Facebook, Microsoft Account, Twitter, Google).

Now add hubConnection as a private variable on the MainPage class (see line 6):

    1: public sealed partial class MainPage : Page
    2: {
    3:     private MobileServiceCollection<TodoItem, TodoItem> items;
    4:     private IMobileServiceTable<TodoItem> todoTable = App.MobileService.GetTable<TodoItem>();
    5:     private MobileServiceUser user;
    6:     private HubConnection hubConnection;

Finally, wire the ConnectToSignalR() method up to OnNavigatedTo(…) in the MainPage class so that it gets called upon app startup after any authentication step (if present):

    1: protected override async void OnNavigatedTo(NavigationEventArgs e)
    2: {
    3:     await AuthenticateAsync();
    4:  
    5:     await ConnectToSignalR();
    6:  
    7:     RefreshTodoItems();
    8: }

If you haven’t wired up authentication then don’t despair – by default the authentication model requires Application Key level access which ConnectToSignalR() takes into account already.

With this you should be able to run your client after which you should see a dialog looking like this:

HelloFromChatHub

Controlling Access Control

You can customize the authentication requirements by setting the required level for all SignalR clients or you can control it per Hub or even per Hub action using the Microsoft.AspNet.SignalR.AuthorizeLevelAttribute, for example, this would require User level authentication for talking to the Send action on the ChatHub:

    1: public class ChatHub : Hub
    2: {
    3:     public ApiServices Services { get; set; }
    4:  
    5:     [AuthorizeLevel(AuthorizationLevel.User)]
    6:     public string Send(string message)
    7:     {
    8:         return "Hello from SignalR Chat Hub!";
    9:     }
   10: }

To set it for all Hubs, set it using the ConfigOptions class in the WebApiConfig.Register method:

    1: public static void Register()
    2: {
    3:     // Initialize SignalR
    4:     SignalRExtensionConfig.Initialize();
    5:  
    6:     // Use this class to set configuration options for your mobile service
    7:     ConfigOptions options = new ConfigOptions();
    8:     options.SetRealtimeAuthorization(AuthorizationLevel.User);
    9:  
   10:     ...
   11: }

Sending Messages from Outside a SignalR Hub

In addition to talking to connection SignalR clients from inside a Hub you can also talk to them from Web API controllers and scheduled jobs. To illustrate this we will send a “hello” message from an ApiController but doing it from a scheduled job works just the same. First add a custom controller to your server project:

    1: public class SampleController : ApiController
    2: {
    3:     public ApiServices Services { get; set; }
    4:  
    5:     public string Get()
    6:     {
    7:         IHubContext hubContext = Services.GetRealtime<ChatHub>();
    8:         hubContext.Clients.All.hello("Hello Chat Hub clients from custom controller!");
    9:         return "Hello from custom controller!";
   10:     }
   11: }

Note that we get the IHubContext from the ApiServices class which is automatically injected into the controller. Now, deploy this and then hit the custom controller in Azure using the help page (you will get prompted for a username and password – for password use the Application Key, the user name doesn’t matter). You can now invoke the custom API:

CustomControllerChatHubIn addition to the response from the controller you should also see a message in your client looking like this:

HelloFromCustomController

Using SignalR Persistent Connections

For more advanced scenarios you can also add a SignalR Persistent Connection which is a lower level abstraction than the Hub. The principle is the same as for Hubs, you just inherit from PersistentConnection instead. A simple example looks like this:

    1: public class TestConnection : PersistentConnection
    2: {
    3:     public ApiServices Services { get; set; }
    4:  
    5:     protected override Task OnConnected(IRequest request, string connectionId)
    6:     {
    7:         base.Connection.Broadcast("Hello!");
    8:         return base.OnConnected(request, connectionId);
    9:     }
   10:  
   11:     protected override Task OnReceived(IRequest request, string connectionId, string data)
   12:     {
   13:         Connection.Broadcast(data);
   14:         return Task.FromResult(true);
   15:     }
   16: }

Scaling up using Service Bus Backplane

If you deploy your service in Basic or Standard tier which supports scale-out to more than one instance then we automatically wire up Azure Service Bus as the backplane for synchronizing the instances:

SignalRScaleOut

You can set the scaling tier for your mobile service using the Scale tab in the Azure Portal:

ScaleTab

That it – your mobile app can now go real-time!

Have fun!

Henrik