Fable.Remoting for .NET Clients

Although Fable.Remoting is initially implemented for communication between a .NET backend and a Fable frontend, the RPC story wouldn't be complete with a strongly typed dotnet client that can talk to the same backend using the protocol definition, that why we have built one.

In fact, you can use the dotnet client with a dotnet server without a Fable project involved, think client-server interactions purely in F#. This has proven to make integration testing extremely simple through this client.


Install the library from Nuget:

paket add Fable.Remoting.DotnetClient --project /path/to/App.fsproj
# or 
dotnet add package Fable.Remoting.DotnetClient

Using the library

As you would expect, you need to reference the shared types and protocols to your client project:

<Compile Include="..\Shared\SharedTypes.fs" />

Now the code is similar the Fable client API with a couple of differences:

open Fable.Remoting.DotnetClient
open SharedTypes

// specifies how the routes should be generated
let routes = sprintf "http://backend.api.io/v1/%s/%s"

// proxy: Proxy<IServer> 
let proxy = Proxy.create<IServer> routes 

async { 
    // length : int
    let! length = proxy.call <@ fun server -> server.getLength "hello" @>
    // 5 
    return length 

The major difference is the use of quotations, which simplified and implementation process greatly and keeps the solution entirely type-safe without fighting with the run-time with boxing/unboxing hacks to get types right.


Alongside the proxy.call approach, there is also proxy.callSafely which is the same but will return Async<Result<'t, Exception>> to catch any exception that occurs along the request:

async {
    let! result = proxy.callSafely <@ fun server -> server.throwError() @> 
    match result with 
    | Ok value -> (* will not match *) 
    | Error ex -> 
        | match ex with 
        | :? Http.ProxyRequestException as requestException -> 
            let statusCode = requestException.StatusCode 
            let response = requestException.Response
            let responseText = requestException.ResponseText
            (* do stuff with the exception information *)
        | otherException -> 
            (* Usually network errors happen here *)

results matching ""

    No results matching ""