Skip to content

Orleans clients

An Orleans client lets application code call grains, use streams, and access other cluster services. Orleans provides a client automatically inside every silo, or you can host an external client in a separate process.

ModelPrefer it whenTradeoff
Co-hosted clientHTTP endpoints, background workers, and grains can share a process.Simplest topology and fastest calls, but client workload shares silo CPU and memory.
External clientFrontends and silos need independent scaling, deployment, security, or resource isolation.Adds gateways, network hops, and another process to operate.

Start with a co-hosted client unless isolation is a requirement.

UseOrleans registers IClusterClient and IGrainFactory in the host service provider:

public static async Task LocalSiloAndClient(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
builder.UseOrleans(siloBuilder =>
{
siloBuilder.UseLocalhostClustering();
siloBuilder.AddMemoryGrainStorageAsDefault();
siloBuilder.UseInMemoryReminderService();
});
var app = builder.Build();
app.MapGet("/hello/{name}", async (string name, IClusterClient client) =>
await client.GetGrain<IHelloGrain>(name).SayHello());
await app.RunAsync();
}

Calls from a co-hosted client use the silo’s cluster knowledge and don’t require a gateway. If the target activation is local, Orleans can also avoid a network hop.

The orleans-web template creates an ASP.NET Core app which co-hosts a silo and exposes a grain through an HTTP endpoint:

Terminal window
dotnet new install Microsoft.Orleans.Templates
dotnet new orleans-web --name HelloOrleans --output HelloOrleans
dotnet run --project HelloOrleans/HelloOrleans.csproj

Call the endpoint from another terminal:

Terminal window
curl http://localhost:5000/hello/Ada

The endpoint returns Hello, Ada!. ASP.NET Core resolves IGrainFactory from dependency injection, the endpoint obtains the grain reference keyed by Ada, and Orleans activates the grain when the request invokes it.

The generated app uses localhost clustering for a one-node development cluster. For a multi-silo deployment, configure shared clustering and storage providers and apply the production-readiness checklist.

Install Microsoft.Orleans.Client, then add the client to the .NET Generic Host with UseOrleansClient:

public static async Task RunExternalClient(string[] args)
{
var builder = Host.CreateApplicationBuilder(args);
builder.UseOrleansClient(clientBuilder =>
{
clientBuilder.Configure<ClusterOptions>(options =>
{
options.ServiceId = "orders";
options.ClusterId = "orders-production";
});
clientBuilder.UseRedisClustering(options =>
{
options.ConfigurationOptions =
ConfigurationOptions.Parse(
builder.Configuration.GetConnectionString("redis")!);
});
});
await builder.Build().RunAsync();
}

The client connects during host startup and is available from .NET dependency injection afterward. Register hosted services that use Orleans after UseOrleansClient so the host starts them after the client:

using Microsoft.Extensions.Hosting;
namespace Client;
public sealed class ClusterClientHostedService : IHostedService
{
private readonly IClusterClient _client;
public ClusterClientHostedService(IClusterClient client)
{
_client = client;
}
public Task StartAsync(CancellationToken cancellationToken)
{
// Use the _client to consume grains...
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
=> Task.CompletedTask;
}

See Client configuration for clustering and gateway settings.

Orleans includes a default connection retry filter. During initial startup it retries eligible connection failures with linear backoff, up to 15 retries. If those retries are exhausted, the host fails to start instead of appearing healthy without a cluster connection.

You can replace the default with UseConnectionRetryFilter or IClientConnectionRetryFilter. Custom policies should:

  • Retry only transient failures.
  • Apply a finite attempt or time limit.
  • Honor the supplied cancellation token.
  • Let startup fail when the cluster or configuration is persistently unavailable.

For generic-host and ASP.NET Core applications, treat IClusterClient as a singleton for the lifetime of the application process. Register it once with UseOrleansClient and resolve it from dependency injection instead of creating a second client per request, per controller, or in a static field.

A web app or worker can safely share the same client across all requests and background services, because Orleans is designed for concurrent use from multiple threads. The client is thread-safe for reuse; protect only mutable application state that you share outside Orleans.

Let the host own client startup and shutdown. The host starts the client during application startup and closes it during normal termination, so you should not dispose the dependency-injected singleton manually. If the cluster is unavailable during startup, the host fails fast rather than leaving the app in a partially started state.

After startup, Orleans refreshes gateways and reconnects as cluster membership changes. If a gateway or silo becomes unavailable, the client tries to reconnect automatically and a transient failure can still surface from an individual grain call. The grain reference remains valid, but retry the operation only if the application can safely tolerate duplicate execution.

External client code isn’t governed by the grain turn-based concurrency model. Multiple threads can use IClusterClient and grain references concurrently. Protect mutable client-side state using normal .NET synchronization.

Grain calls return Task, Task<T>, ValueTask, or ValueTask<T> according to the grain interface rules. Always await calls rather than blocking threads.

Use grain observers for best-effort, one-way callbacks to client objects. Add application-level acknowledgement or recovery when delivery matters. Use streams when the stream provider’s subscription and delivery model better fits the workflow.

Let the Generic Host own client startup and shutdown. Don’t create a client per request, cache a second client in a static field, or dispose the dependency-injected singleton. When the host receives a termination signal, it closes the client as part of normal shutdown.