/signalrprovider

F# Type Provider for SignalR with FunScript

Primary LanguageF#Apache License 2.0Apache-2.0

signalrprovider

F# Type Provider for SignalR with FunScript

Type provider giving a typed view of a .NET SignalR server Hub (could be C# or F#) to client-side code compiled from F# to JavaScript with FunScript.

It more or less gives the effect of generating TypeScript definitions for the hubs for which tools exist, and generating FunScript bindings for these definitions, except updating smoothly on a simple build of the server DLL.

Build status

How it works

Server project defines a SignalR Hub class:

open Microsoft.AspNet.SignalR

[<HubName("myhub")>]
type MyHub() = 
    inherit Hub()
    
member this.frob(x: int) = 42 + x

The client uses FunScript, the FunScript bindings for SignalR, and has a reference to the server. The client references the SignalRProvider, which searches for hubs (by attribute) in the referenced DLLs, and exposes these

let signalR = Globals.Dollar.signalR  // FunsScript binding for SignalR TypeScript definition
let serverHub = new Hubs.myhub(signalR.hub) // Hubs.myhub type generated by SignalRProvider from above definition

Then when a method on the hub is called, it will be typechecked at compile time of the FunScript code.

serverHub.frob(10); // OK
serverHub.frob("string") // Fail to compile
serverHub.foo(10) // Fail to compile

When it comes to client hubs an interface type can be defined in the server hub DLL. This should be used as the parameter to a SignalR strongly typed hub Hub<IMyHubClient>:

type IMyHubClient =
    abstract member ClientMethod : string -> void

type MyHub() = 
    inherit Hub<IMyHubClient>()
    
    member this.frob(x: int) = this.Clients.All.ClientMethod "hello"

Then on the client side a type is generated MyHubClient with setters for the interface methods and a method to register the hub:

let client = Hubs.MyHubClient()
client.ClientMessage <- (fun msg -> Globals.console.log(msg))
client.Register(signalR.hub)

Issues

  • Reflection to examine referenced assemblies is a horrible appdomain-creating mess. I hope I got it right, it was painful enough. I think assemblies only get locked when 2nd copy of VS attached to debug TP.
  • Return types of deferred object not right yet.
  • Assumes all hubs defined are available at the configured hub URL