Strongly Typed SignalR Hubs with TypeScript

SignalR is a great piece of kit for rapidly developing a push communication layer for a user interface. However there are a couple of things we would like it to do better:

  • Build time generation of hub proxies instead of dynamic runtime generation
  • Strongly typed JavaScript data contract and service definitions

The major problem with the dynamic hub proxy generation is that if the service is down and can't respond with the JavaScript then your page will actually break on load because the JavaScript you have written to hook up to the hub client methods will be full of null reference exceptions, unless of course you litter your code with horrible null checks. Due to this you don't have the opportunity to show a good connection error message to the user because your app can't even start. A much better solution would be to generate these at compile time and distribute them via internal package feeds to include during the front end build. You can then rely on the hub definitions always being there.

The loose typing issue can easily be solved with the use of TypeScirpt. We have started using TypeScript to produce all of our front ends which is proving to be incredibly successful at reducing bugs. SignalR doesn't provide any support for producing TypeScript definitions at the moment and the only tools I found on GitHub were not quite right for us so I forked the best one I found and have made some changes to support our requirements.

SignalR.ProxyGenerator

This project is quite straight forward. SignalR provides a default HubManager that generates the JavaScript proxies for you but I have wrapped it to provide more configurable build time support. The console application loads the assembly you are generating proxies for and all of it's dependencies, then generates the proxies and strips out all of the generated comment information because the reference paths to jQuery may not be correct in your environment and could break your build. There are also arguments to specify the default connection url and additional metadata comments you would like included at the top of the file.

Find it here on GitHub: geniussportsgroup/SignalR.ProxyGenerator

Signalr.Hubs.TypeScriptGenerator

The tool I forked by yetanotherchris did the job that I was looking for however he has only generated a pre-release NuGet package. I also wanted functionality for the TypeScript generator to respect DataMember attributes with the member Name overridden. We serialize using camelCase and instead of relying on a serializer behaviour I wanted to do this using the serialization attributes:

[DataContract]
public class SomethingDto
{
    [DataMember(Name = "iChangedTheName")]
    public string Property1 { get; set; }

    [DataMember]
    public Guid Property2 { get; set; }
}

Will produce the following:

declare module GeniusSports.Signalr.Hubs.TypeScriptGenerator.SampleUsage.DataContracts
{
    interface SomethingDto
    {
        iChangedTheName : string;
        Property2 : System.Guid;
    }
}

I've also changed the d.ts file include paths to more standard conventions, if anyone needs customizable paths then we can easily add support for that.

/// Autogenerated at 16/09/2016 13:22:56 by https://github.com/geniussportsgroup/Signalr.Hubs.TypeScriptGenerator
/// <reference path="../signalr/index.d.ts" />
/// <reference path="../jquery/index.d.ts" />

Find it here on GitHub: geniussportsgroup/Signalr.Hubs.TypeScriptGenerator

Putting It All Together

At compile time of our C# back end SignalR hubs we now generate the hub proxies and TypeScript definitions. These are published to an internal Nexus NPM repository which our front end team can easily use to consume the packages in their build pipeline. The packages are also versioned using the semver convention allowing much better tracking of which versions of our APIs we can attribute issues to. We now have a full continuous integration cycle protecting us from accidental breaking changes and a self documenting API for our front end team to use.

Both of the GitHub projects have well documented readme files for full details.

comments powered by Disqus