I’ve been building an FSharp Dashboard by following along this post from Louie Bacaj’s which was part of last years FSharp Advent calendar. I have to say it’s a great post and has got me up and running in no time.

If you want to skip the story and get to the FSharp and SignalR part scroll down to Changing the Hub.

One small problem I noticed was that I could not use any of the features of FSharp Core v4. For example, the new tryXXX functions such as Array.tryLast were not available.

After a bit of digging I happened across the Project Properties which were stuck on 3.1.2.1.

Project Properties

Turns out that the FSharp.Interop.Dynamic package is dependant on FSharp.Core v3.1.2.1.

So this turned into a challenge of how do I use SignalR without Dynamic. After a bit of googling I landed on this page that showed Strongly Typed Hubs. So I knew it was possible…

Removing Dependencies

The first step to fixing this was to remove the FSharp.Core dependencies I no longer needed, these were:

Uninstall-Package FSharp.Interop.Dynamic 
Uninstall-Package Dynamitey
Uninstall-Package FSharp.Core

I then just browsed through the source and removed all the open declarations.

Re-adding FSharp Core

Slight problem now, I no longer had any FSharp Core references, so I needed to add one in. I’m not sure if this is the best way to solve this, but I just copied and pasted these lines from a empty FSharp project I just created:

<Reference Include="mscorlib" />
<!--Add this bit-->
<Reference Include="FSharp.Core, Version=$(TargetFSharpCoreVersion), Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
    <Private>True</Private>
</Reference>
<!--End-->
<Reference Include="Newtonsoft.Json">

Changing the Hub

Now all I had to do was update the code to use the statically typed hub.

First step was to create an interface for the metricsHub:

type IMetricsHub = 
    abstract member AddMessage: string -> unit
    abstract member BroadcastPerformance: PerfModel seq -> unit

Then change our Hub to inherit from the generic Hub<T>:

[<HubName("metricsHub")>]
type metricsHub() = 
    inherit Hub<IMetricsHub>() // < Generic version of our interface.

And changed all the calls from:

Clients.All?message(message)

to

Clients.All.Message message

Getting the Context

With SignalR you cannot just new up an instance of a Hub, you have to use GlobalHost.ConnectionManager.GetHubContext<THub>. The problem is that this gives you and IHubContext which only exposes the dynamic interface again. A bit more googling and I found that you need to pass our interface as a second generic parameter and you will get an IHubContext<IMetricsHub>.

So this:

let context = GlobalHost.ConnectionManager.GetHubContext<metricsHub>()

Becomes:

let context = GlobalHost.ConnectionManager.GetHubContext<metricsHub, IMetricsHub>()

Now you can call Context.Clients.All.BroadcastPerformance and not worry about that pesky dynamic any more.

Conclusion

The documentation on SignalR isn’t very good, it was easy enough to find out about the statically typed version, but finding out how to get one out of the context was a right pain.

I’ve published a fork of Louies GitHub repo with four commits that show the steps needed to move from dynamic to statically typed SignalR here so you can see the changes I needed to make.