Getting Started with SignalR using F# and OWIN

SignalR allows us to easily push messages back and forth between a client (usually a website) and server using websockets. All of the pain of creating a connection, keeping the connection alive, reconnecting, serialising and deserialising messages, plus lots, lots more is taken care of for you.

In this post we're going to create a SignalR server and push some messages back and forth from a website. You can see the completed source at github.com/troykershaw/signalr-fsharp-getting-started.

Note: This will probably only run on Windows.

Get the project set up

  • Create a new console application. I chose to use .NET 4.6.1, but anything in the 4.x range should work.

Hello, Paket

We're going to use Paket to download and manage our dependencies. Compared to nuget Paket requires a little effort to set up for a new project but it's totally worth it. Here's how to do it, basically pulled straight from Paket's Getting Started page

  • Open a command window (because it's hard to create a folder with a dot in front of it from Windows Explorer)
  • Create a .paket folder in the root of your solution (mkdir .paket).
  • Download the latest paket.bootstrapper.exe into that folder.
  • Run .paket/paket.bootstrapper.exe. This will download the latest paket.exe.
  • Commit .paket/paket.bootstrapper.exe into your repo and add .paket/paket.exe to your .gitignore file.
  • Create a paket.dependencies file in your project's root and paste in the following:
source https://nuget.org/api/v2

nuget Microsoft.AspNet.SignalR.SelfHost  
nuget Microsoft.Owin.Cors  
nuget Microsoft.Owin.StaticFiles  
nuget FSharp.Interop.Dynamic  
  • In your project create a file named paket.references and paste in the following:
Microsoft.AspNet.SignalR.SelfHost  
Microsoft.Owin.Cors  
Microsoft.Owin.StaticFiles  
FSharp.Interop.Dynamic  
  • Run the command .paket\paket.exe install to install all the dependencies.

Now you've got everything you need for the rest of this blog post.

Let's get the server running

SignalR is part of the ASP.NET family and runs nicely in a standalone OWIN server, so let's do that.

  • Create a new file called Signalr.fs and put it above `Program.fs.
  • Here's all we need to get the server running, so paste it in

source https://nuget.org/api/v2

nuget Microsoft.AspNet.SignalR.SelfHost  
nuget Microsoft.Owin.Cors  
nuget Microsoft.Owin.StaticFiles  
nuget FSharp.Interop.Dynamic  

But of course that won't do anything yet.

  • Open Program.fs and make it look like:

paket.references

Now you can run it, and get a loose confirmation that it worked because it printed something to the Console window.

What's happening is Program.fs creates an instance of our SignalR server and then doesn't exit because it's waiting for you to press Enter. Signalr.fs creates a startup function that enables CORS and enables Signalr, then we start the OWIN server using that configuration.

Send some messages to a web page

To actually be useful let's send a message to a web page. We, of course, first need to create a web page and some way of serving that page. We could just tack it on to our current SignalR server but because OWIN servers are so easy to write let's create a new one.

  • Create a new file called Static.fs, put it above Program.fs and paste in the following:

Microsoft.AspNet.SignalR.SelfHost  
Microsoft.Owin.Cors  
Microsoft.Owin.StaticFiles  
FSharp.Interop.Dynamic  

We now have a server that serves static files. Let's start it.

  • In Program.fs add let staticServer = Static.Server "http://localhost:8777" after the SignalR server.
  • Create an index.html page and set the property Copy to Output Directory to Copy always.
  • Also, paste in the following:

.paket\paket.exe install

When you go to http://localhost:8777/index.html you'll get a blank web page! Yay!

MyFirstHub

The SignalR client and server relationship communicates over 'hubs', so let's create one of those.

  • Within the Signalr.fs file and above the Server class put this:

Signalr.fs

The MessageToTheServer method is what SignalR clients call. If you run our app now and refresh the web page the web page will send the message "Hello from the client!" to our server which you can confirm is happening because it prints it to the console.

Sending messages

Sending messages to our clients is quite easy, we don't even need to update our hub. What we will do, however, is create a method that consumers of our server can call to send a message.

  • Above the do in the SignalR Server class put:

Program.fs This gives us an easy way to get to our clients.

  • Right at the bottom of the class put:

Program.fs

In the Send method we simply push the message to all clients (clients.All) and call the function messageToTheClient on the client.

Let's call signalr.Send in Program.fs. Actually, let's send a message every second.

  • Replace System.Console.ReadLine() |> ignore with

Enter

Run our app, refresh the page and the server message appears on the screen. Magic!

Debugging in Chrome

It's easy to see what's being sent to the client from the server in Chrome.

Go to our webpage, open dev tools (Ctrl + Shift + I), select the 'Network' tab and select the 'WS' filter.

Reload the page and you'll see something pop up under 'Name' that reads similar to 'connect?transport=webSockets&clientProtocol=1.5&connectionToken=...'. Select it and then press 'Frames' just to the right of it.

Sure enough, at the top of the list we see the message the client sent and every second after that we see a new message from the server. The {} messages are a 10 second heart beat.

Sending something a little more interesting

Sending a string is fun but there's not a lot we can do with that. Let's send something a little more complex.

We've had too much excitement up until now so I'll bring the mood down a bit by creating a boring Customer type.

  • Create a new file above all the others called Customer.fs and enter the following

Signalr.fs

  • In Program.fs put an open Customer at the top of the file and replace the current message we're sending ("The server says hello!") with the following:

startup

Now when we run the app our web page gets the customer message as nice looking json:

Static.fs

Sending F# things

What happens when we send F# specific things though?

Program.fs

  • Update the message we're sending in Program.fs to:

Program.fs

Run everything again.

It worked! Although the json is really, really ugly.

let staticServer = Static.Server "http://localhost:8777"

Look at all of those Cases and Fields. Yuck.

The good news and the bad news

The good news is that we can serialise and deserialise our Customer record into really clean json. The bad news is that you're going to have to wait for the next installment.

Remember you can check out the source for this post at github.com/troykershaw/signalr-fsharp-getting-started.

Merry Christmas everyone!

comments powered by Disqus