I had some difficulty getting SignalR set up with a recent web application being developeed for a client. Some of the documentation found online were geared towards older versions of SignalR, while others didn’t seem to work with my setup.
I am creating additional functionality for a web client that allows a server to push information to a client when certain events trigger. Being a MVC and HTML5 application I decided to utilize Web Sockets.
- With Visual Studio 2012 I installed the SignalR nuget package to speed up the installation.
- I created a Startup.cs file in the project’s App_Start folder placing the following code inside of it:
using Microsoft.AspNet.SignalR; using Microsoft.Owin; using Owin; using Desking.SignalR; [assembly: OwinStartup(typeof(Desking.Startup))] namespace Desking { public class Startup { public void Configuration(IAppBuilder app) { app.MapSignalR(); } } }
- SignalR has the ability to dynamically generate the hub js file found at signalr/hub at the applications root used for talking to the server, but the generated file was not minified and I couldn’t find a way to integrate it with MVC’s script bundles I use across the application. I decided instead to take the dynamically generated file and place into a normal js file.
- At the end of the hub.js file I needed to modify the relative path url
signalR.hub = $.hubConnection("/applicationPath/signalr", { useDefaultPath: false });
- I created the following hub file:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using Microsoft.AspNet.SignalR; using Microsoft.AspNet.SignalR.Hubs; using Desking.Models; namespace Desking.SignalR { [HubName("deskingHub")] public class DeskingHub : Hub { public void sendNotification(String Name, String Message) { Clients.Client(Context.ConnectionId).addMessage(Name + ": " + Message); } public void registerClient(long DeskingDraftRevisionID) { DealMethods.RegisterClient(DeskingDraftRevisionID, Guid.Parse(Context.ConnectionId)); } public enum Statuses { FinancingConfirmed = 0, NeedManager, ReadyForDocuments, } } }
- The registerClient method is used when the client first loads the application by registering and linking the draft id they have opened to the connection ID generated by SignalR. This allows the server to send notifications based on the draft id needing to be notified
- The following js is included on the initial page load:
function SetupFinancingNotifications() { // Declare a proxy to reference the hub. var chat = $.connection.deskingHub; // Create a function that the hub can call to broadcast messages. chat.client.addMessage = function (message) { alert(message); }; // Start the connection. $.connection.hub.start().done(function () { chat.server.registerClient($('#labelDealStatusQuoteNumber').text()); $('#sendmessage').click(function () { // Call the Send method on the hub. chat.server.sendNotification($('#displayname').val(), $('#message').val()); // Clear text box and reset focus for next comment. $('#message').val('').focus(); }); }); }
- The js registers itself with the server given the revision id currently opened. The SignalR’s client instance ID is taken from the request context on the server side and isn’t needed to be pass in manually.
- After the client is set up all that is left to do is create a method that will signal the web client:
public static void NotifyClient(long DealID, DeskingHub.Statuses DealStatus, String Message) { using (CRMEntities db = new CRMEntities()) { DeskingDraftFinancingNotification notification = db.DeskingDraftFinancingNotifications.Where(x => x.DealID == DealID).FirstOrDefault(); if (notification != null) { try { IHubContext notificationHub = GlobalHost.ConnectionManager.GetHubContext<DeskingHub>(); notificationHub.Clients.Client(notification.ConnectionID.ToString()).addMessage(DealStatus, Message); } catch (Exception ex) { ex.LogToElmah(); } } } }
In the future I will need to add more functionality to allow client -> server communication, as well as getting SignalR to function behind a load balancer across 3 servers using the SQL backplane.