SignalR in ASP.NET Core 2

I had a chance to work with the latest SignalR library for ASP.NET Core 2 which is in Alpha as I write this. My customer is looking at Azure and I thought it would be good to showcase a PaaS workload using Azure Functions and Azure App Services. You can see the application on Github here.

The app will simulate the tracking of a Paraglider flight which I simply downloaded off the XC league website (thanks Graham Steel). The Azure Function will be triggered by a new track log in Blob Storage and for each entry it sends the coordinates to the website at the right intervals. The call to the website triggers a broadcast to registered clients so that JavaScript on the page can update the map with the new pin location.

The Hub class

I needed to create a class that inherits from Hub and register an endpoint for clients to connect to when they want to start listening for messages. The Startup class is used to set up the endpoint "/gps".

            app.UseSignalR(routes => 


The LocationController receives the request from the Azure Function so it needs to be able to broadcast to the SignalR clients. Ideally, it would have been great to configure my Function to broadcast to all clients itself but my Function is .NET 4.6.1 so it was a whole lot simpler just to call an API endpoint in my website. Once Functions are fully .NET Core I'll see if I can make that happen but for now I'll just take the hit of an extra call to the website's LocationController.

In this example we are using Web Sockets but that is transparent to the controller. In fact all the transport and protocol concerns are taken away and all I have to care about is the object I want to send which is nice. Everything seems clean and simple with the new SignalR code.

You can see here how the IHubContext is used to invoke the client and trigger a a "Send" method...

public class LocationController : Controller
        private readonly IHubContext<Locator> _hubContext;
        public static IConfiguration Configuration { get; set; }
        private readonly IFileProvider _files;

        public LocationController(IHubContext<Locator> hubContext, IConfiguration configuration, IFileProvider files)
            _hubContext = hubContext;
            Configuration = configuration;
            _files = files;
        // api/location/5101/00012
        [HttpGet("{id}/{lat}/{lon}", Name = "GetLocation")]
        public async Task<ObjectResult> SendLocation(string id, string lat, string lon)
            var item = new { Pilot = id, Latitude = lat, Longitude = lon };
            await _hubContext.Clients.All.InvokeAsync("Send", $"{item.Pilot}&{item.Latitude}&{item.Longitude}");

            return new ObjectResult(item);

Client Side

async function GetMap() {
        let connection = new signalR.HubConnection('/gps');

        map = new Microsoft.Maps.Map('#myMap', {
            credentials: '@ViewData["MapKey"]',
            mapTypeId: Microsoft.Maps.MapTypeId.aerial,
            zoom: 10
        recenterAfter = 0;

        connection.on('send', track => {

            var pilot = track.split("&")[0];
            var latestLoc = new Microsoft.Maps.Location(track.split("&")[1], track.split("&")[2]);
            if (!userPin[pilot]) {
                userPin[pilot] = new Microsoft.Maps.Pushpin(latestLoc, { visible: true, color: getColour(pilot) });
                    center: latestLoc,
                    zoom: 15

            userPin[pilot].data = track.split("&");


In the browser I need to set up a connection to my SignalR hub and listen for calls to "send" at which point a function is triggered, "track", that pulls out the pilot name, latitude and longitude from the message and sets the new location for the map's pin. I support a couple of pilots which is just the same track but with different pilot name. The GetMap() function is just a callback used to start updating the map once the Bing Map loads.


In case anyone has a similar problem I will make a quick mention of a problem I had. Not looked into it that much but I think a change in ASP.NET Core 2 affected the way in which file providers are dealt with so it took a little searching to figure it out how to inject an IFileProvider into my controller. I had to implement the following in Startup.

new PhysicalFileProvider(Directory.GetCurrentDirectory())); 

Featured Posts
Recent Posts