Skip to content
Orleans.FSharp

Guide to the clientConfig { } computation expression.

  • How to configure an Orleans client to connect to a silo
  • Clustering modes: localhost, static gateways
  • TLS for secure client connections
  • Custom DI services on the client

The clientConfig { } CE builds a ClientConfig record. Apply it to a host or build it directly:

open Orleans.FSharp.Runtime
let config = clientConfig {
useLocalhostClustering
}
// Option 1: Apply to a HostApplicationBuilder
let builder = HostApplicationBuilder()
ClientConfig.applyToHost config builder
// Option 2: Build directly (creates a host and returns the client)
let host, client = ClientConfig.build config
host.StartAsync().GetAwaiter().GetResult()

Connect to a single local silo for development:

clientConfig { useLocalhostClustering }

Connect to known silo endpoints:

clientConfig {
useStaticClustering [ "10.0.0.1:30000"; "10.0.0.2:30000" ]
}

Each endpoint must be in "host:port" format.


clientConfig {
useLocalhostClustering
clusterId "my-cluster"
serviceId "my-service"
}

The clusterId and serviceId must match the silo configuration.


How often the client refreshes its list of available gateways:

clientConfig {
useLocalhostClustering
gatewayListRefreshPeriod (TimeSpan.FromSeconds 30.)
}

Set the preferred gateway index for client connections:

clientConfig {
useLocalhostClustering
preferredGatewayIndex 0
}

clientConfig {
useLocalhostClustering
addMemoryStreams "StreamProvider"
}

clientConfig {
useLocalhostClustering
useTls "CN=my-client-cert"
}
let cert = new X509Certificate2("path/to/cert.pfx", "password")
clientConfig {
useLocalhostClustering
useTlsWithCertificate cert
}
clientConfig {
useLocalhostClustering
useMutualTls "CN=my-client-cert"
}

Select one generalized-serialization policy. AddFunctionalGrainClient installs the binary functional default; configure an explicit policy only when this client should choose a different codec for ungenerated application types:

let serialization =
FSharpSerialization.Binary
|> FSharpSerialization.forUnsupportedTypes FSharpSerialization.Json
clientConfig {
useLocalhostClustering
useFSharpSerialization serialization
}

The client and silo must select the same policy. Use useFSharpJsonSerialization when JSON should be the primary generalized codec. See Serialization.


Register services on the client’s DI container:

clientConfig {
useLocalhostClustering
configureServices (fun services ->
services.AddSingleton<IMyService, MyService>() |> ignore)
}

Calling a functional grain from a client-only process

Section titled “Calling a functional grain from a client-only process”

clientConfig { } configures the connection; the functional transport is installed separately, on the IClientBuilder, with AddFunctionalGrainClient(). A process that also hosts the definition needs nothing extra – AddFunctionalGrain on the silo builder installs the client transport too.

open Orleans.FSharp
builder.UseOrleansClient(fun clientBuilder ->
clientBuilder.AddFunctionalGrainClient() |> ignore)
|> ignore
// Then bind the typed API record against the connected client.
let api = CounterApi.ref client "my-counter"

The call is idempotent, and it fails at configuration time with a diagnostic naming IGrainReferenceActivatorProvider if it runs before Orleans has installed its own reference activators. See Functional Grain Runtime.


open System
open System.Threading.Tasks
open Orleans
open Orleans.FSharp
open Orleans.FSharp.Runtime
open Microsoft.Extensions.DependencyInjection
open Microsoft.Extensions.Hosting
type CounterActor = private CounterActor of unit
[<NoEquality; NoComparison>]
type CounterApi = { increment: unit -> Task<int> }
[<RequireQualifiedAccess>]
module CounterApi =
let contract =
grainContract<CounterActor, string, CounterApi> {
grainType "counter"
version 1
stringKey
}
let ref = FunctionalGrain.ref contract
let config = clientConfig {
useStaticClustering [ "10.0.0.1:30000"; "10.0.0.2:30000" ]
clusterId "production"
serviceId "my-app"
useMutualTls "CN=orleans-client"
gatewayListRefreshPeriod (TimeSpan.FromSeconds 30.)
addMemoryStreams "Events"
}
let builder = HostApplicationBuilder()
ClientConfig.applyToHost config builder
builder.UseOrleansClient(fun clientBuilder ->
clientBuilder.AddFunctionalGrainClient() |> ignore)
|> ignore
let host = builder.Build()
host.Start()
let client = host.Services.GetRequiredService<IClusterClient>()
let counter = CounterApi.ref client "my-counter"
let result = counter.increment().GetAwaiter().GetResult()