Self hosting SignalR

I’ve covered the steps needed to host SignalR within a web application, but we’ve also seen we can connect to SignalR through a .NET client (in my case a simple Console app.). So next we’ll cover self-hosting SignalR.

Requirements

At the time of writing you’ll need to install the following NuGet packages from Package Manager Console in Visual Studio

Install-Package Microsoft.AspNet.SignalR
Install-Package Microsoft.Owin.Hosting -Pre
Install-Package Microsoft.Owin.Host.HttpListener -Pre

You can delete the scripts folder added by SignalR, we’re really just after the assemblies

Microsoft.AspNet.SignalR.Core
Microsoft.AspNet.SignalR.Owin
Microsoft.Owin.Host.HttpListener
Microsoft.Owin.Hosting
Owin

So if you feel like only deploying the minimal assemblies you can remove anything else installed from those packages.

Edit: Since writing the above a couple of things seems to have changed on those packages, you’ll now need Microsoft.Owin assembly and WebApplication (in the below code) is now WebApp.

The Server

public class MyHub : Hub
{
   public void Send(string message)
   {
      Clients.All.sendMessage(message);
   }
}

internal class MyStartUp
{
   public void Configuration(IAppBuilder app)
   {
      // the line below works fine with the console client but not the browser client
      // app.MapHubs();
      // use the following to enable the browser client to work with the server
      HubConfiguration config = new HubConfiguration();
      config.EnableCrossDomain = true;
      config.EnableDetailedErrors = true;
      app.MapHubs(config);   
   }
}

class Program
{
   // just for demo purposes, will "beep" every 5 seconds
   private static Timer timer = new Timer(o =>
   {
      var context = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
      context.Clients.All.sendMessage(DateTime.Now.ToLongTimeString() + " beep");
   });

   static void Main(string[] args)
   {
      using (WebApplication.Start<MyStartUp>("http://localhost:9100"))
      {
         // just for this demo
         TimeSpan ts = TimeSpan.FromSeconds(5);
 	 timer.Change(ts, ts);

	 Console.WriteLine("Server is running, Press <Enter> to stop");
	 Console.ReadLine();
      }
   }
}

I’ve listed all the code above, it’s all pretty self-explanatory. The URL in the start method is the URL for the server and port etc. The timer is solely used to send out a message every 5 seconds for out client to see. I’ve listed the code for a simple client below (see my post on creating a .NET client for SignalR if you need more info. on this).

Client

A simple .NET Console client…

static void Main(string[] args)
{
   HubConnection connection = new HubConnection("http://localhost:9100");
   IHubProxy proxy = connection.CreateHubProxy("myHub");
   connection.Start().ContinueWith(task =>
   {
      proxy.Invoke("Send", ".NET Client Connected");

      proxy.On<string>("sendMessage", (message) =>
      {
         Console.WriteLine(message);
      });
   });
   Console.Read();
}

If, you wish to access the server hub via JavaScript then the following is a simple example of the required JavaScript, note we create the proxy to the hub in the same way to the way we do this in the console client.

<script>
   $(function () {
      var connection = $.hubConnection("http://localhost:9100");
      var proxy = connection.createHubProxy('myHub');

      proxy.on("sendMessage", function (message) {
         $('#discussion').append('<li><strong>' + message + '</strong></li>');
      });

      connection.start().done(function () {
         proxy.invoke("Send", "Webpage client");
      }).fail(function () {
         $('#discussion').append('<li><strong>Failed to start</strong></li>')
      });
   });
</script>

Note: The at least one proxy.on event handler must be set before the connection.start or you will be able to send messages but not receive them (see http://www.asp.net/signalr/overview/hubs-api/hubs-api-guide-javascript-client#establishconnection for more information).