Broadcast from an ASP.NET Web API to a UWP Client using SignalR 2

I recently had to take an existing ASP.NET Web API (not core) that was used by a UWP (Universal Windows Platform) client to pull information and modify it to receive notifications from the Web API under some situations. This post is going to cover the creation of a Web API and UWP projects and the modification of the projects to allow notification from the Web API to the UWP client.

Web API Project Creation

In Visual Studio we need to create a new project for the Web API using File > New > Project.

We will be creating an ASP.NET Web Application (.NET Framework) and I’m just naming the project Web API.

On the next screen select that we want a Web API application.

UPW Project Creation

As above in Visual Studio we need to create a new solution and project for the UWP Client using File > New > Project from a new instance of Visual Studio. Select the Blank App (Universal Windows) template.

Next, you will be prompted for the versions of Window 10 to support with the UWP application. I just took the defaults.

You may also want to set your PC into Developer mode.

Add SignalR to the Web API

Now that the initial project creation is done let’s add SignalR to the WebApi project. Inside of Visual Studio right-click on the project and select Manage NuGet Packages.  Select the Browse tab and in the search box enter SignalR and we are looking for the Microsoft.AspNet.SignalR package. Select it and click the Install button.

Configuration

Now that SignalR is installed it needs to be configured on startup of the application. To do this add a Startup class if it doesn’t exist with the following contents.

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        var hubConfiguration = new HubConfiguration
        {
            EnableDetailedErrors = true,
            EnableJavaScriptProxies = false
        };
        app.MapSignalR(hubConfiguration);

    }
}

The hubConfiguration bit is only needed if you want to change the default settings. In this example, we don’t have any JavaScript clients so we don’t need those proxies and we are learning so detailed errors will come in handy.

Hub

The first thing we need to do is create a new hub which is what SignalR uses to do all of its magic. Hubs are what enable the server (and/or client depending on how you are using it) to make remote calls. Since we are just doing a broadcast the hub class is empty except for a reference to the class that will be handling when to send the broadcast. This property is very important since it will be the trigger for Broadcaster to get instantiated when a client connects.  The following is the full class.

using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;

namespace WebApi.Hubs
{
    [HubName("BroadcastHub")]
    public class BroadcastHub : Hub
    {
        private readonly Broadcaster _broadcaster = Broadcaster.Instance;
    }
}

Make note of the hub name used as we will need it on the client side.

Next, we have the class that actually does the broadcasting. The following is the full class.

using System;
using System.Threading;
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;

namespace WebApi.Hubs
{
    public class Broadcaster
    {
        private readonly TimeSpan _updateInterval = 
            TimeSpan.FromMilliseconds(250);
        private Timer _timer;

        private static readonly Lazy<Broadcaster> _instance = 
            new Lazy<Broadcaster>(() => new Broadcaster(GlobalHost.ConnectionManager.GetHubContext<BroadcastHub>().Clients));
        public static Broadcaster Instance => _instance.Value;

        public IHubConnectionContext<dynamic> Clients { get; set; }

        public Broadcaster(IHubConnectionContext<dynamic> clients)
        {
            Clients = clients;
            _timer = new Timer(Broadcast, null, _updateInterval, _updateInterval);
        }

        public void Broadcast(object state)
        {
            Clients.All.Broadcast(DateTime.Now);
        }
    }
}

The above is a singleton which gets created with the list of clients for a specific hub which can be seen in the following line. It has been reformatted from above to try and make it a bit more readable.

private static readonly Lazy<Broadcaster> _instance = 
  new Lazy<Broadcaster>(() => 
             new Broadcaster(GlobalHost
                            .ConnectionManager
                            .GetHubContext<BroadcastHub>()
                            .Clients));

The constructor of the class sets up a timer that calls a Broadcast function which sends the current date and time to all the connected clients. This could be any sort of data, but for this sample, I’m keeping it simple.

Add SignalR to the UWP Client

Now over in the UWP project, we need to add the SignalR client by right-clicking on the project and selecting Manage NuGet Packages. As in the Web API instructions above search for SignalR using the Browse tab. Select the Microsoft.AspNet.SignalR.Client package and click Install.

UI

To keep the sample as simple as possible we are just going to add a TextBlock to the MainPage.xaml to display the results of the broadcast from the Web API. The following is the full code for the page.

<Page
    x:Class="UwpClient.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:UwpClient"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBlock Name="BroadcastResults" />
    </Grid>
</Page>

Now in the code behind we need to connect to the hub on the Web API and define what happens when a broadcast is received. The following is all of the code in the code behind which will be followed up with some comments.

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();
        InitilizeHub();
    }

    private async void InitilizeHub()
    {
        var hubConnection = new HubConnection("http://localhost:50869");
        var hubProxy = hubConnection.CreateHubProxy("BroadcastHub");

        hubProxy
        .On<DateTime>("Broadcast",
                      async data => 
                            await Dispatcher
                                  .RunAsync(CoreDispatcherPriority.Normal,
                                            () => BroadcastResults.Text = 
                                                          data.ToString()));
        await hubConnection.Start();
    }
}

The hubConnection as you might expect controls the connection with the server and the hubProxy deals with the interaction with a specific hub. In our case, we are saying with the Broadcast function is called on the server we want the client to update the BroadcastResults.Text with the value from the server.

Wrapping Up

Run the Web API and then UWP application and you will see the date time from the server being shown on the client. This is, of course, is the simplest of use cases for SignalR, but it is a great jumping off point to go deeper.

This tutorial from the official docs helped a lot when getting my sample up and running.

The code for this sample can be found here.


Also published on Medium.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.