---
title: "Orleans.Lattice.Api.Replication.Grpc"
url: "https://nsta1.github.io/Orleans.Lattice/docs/lattice.api.replication.grpc/README.html"
source: "https://github.com/NSTA1/Orleans.Lattice/blob/release/9.9/docs/lattice.api.replication.grpc/README.md"
package: "Orleans.Lattice.Api.Replication.Grpc"
version: "9.9.0"
documents: "Orleans.Lattice 9.9.0 (release line 9.9)"
built: "2026-10-04"
all-pages: "https://nsta1.github.io/Orleans.Lattice/llms.txt"
bundle: "https://nsta1.github.io/Orleans.Lattice/docs/lattice.api.replication.grpc/llms-full.txt"
---
# Orleans.Lattice.Api.Replication.Grpc

Part of the [documentation map](../index.md).

Code-first gRPC binding for [Orleans.Lattice.Api.Replication](../lattice.api.replication/README.md) - projects the runtime replication control facade onto a gRPC service and a public typed client, over the same Orleans-serialized records, with no hand-written `.proto`.

## What is it?

`Orleans.Lattice.Api.Replication.Grpc` is the remote transport for the cluster's replication control plane. A host references it when a dashboard, a CLI, or an internal admin service needs to enable and disable per-tree replication, inspect the replicated set, or read each replication link's status over the network rather than in-process.

It provides:

- **A code-first gRPC service.** One unary RPC per facade operation, bound from C# definitions rather than a `.proto`.
- **A public typed client.** `LatticeReplicationApiGrpcClient` exposes one method per RPC over a caller-supplied gRPC `CallInvoker`.
- **Shared Orleans marshalling.** Every message is a `[GenerateSerializer]` record - one of the package's wire records, or, for peer status, the facade's own query and page records - serialized with the Orleans binary serializer, so client and server stay in lock-step by construction.
- **Two-layer, fail-closed authorization.** A transport meta-authorizer gates every operation RPC at the edge and defaults to deny. The facade's own access gate then re-authorizes the resolved caller; it denies by default once an authorization add-on such as `Orleans.Lattice.Auth` supplies it (with only the core no-op gate registered it allows every call).

Enabling and disabling replication reconfigures cross-cluster data flow, so the binding fails closed: with no authorizer registered, every operation RPC is rejected with `PermissionDenied`.

## Core properties

- **Public clients, internal services.** Callers consume `LatticeReplicationApiGrpcClient` and, for peer status, `LatticeReplicationStatusGrpcClient`; the services, marshallers, method definitions, and interceptor are internal.
- **No transport policy in the client.** Address, TLS, retries, deadlines, and credentials live on the caller's `GrpcChannel` / `CallInvoker`.
- **Two load-bearing gates.** The transport meta-authorizer decides whether a call may run at all; the credential the identity bridge resolves then feeds the facade's own fail-closed access gate. Neither replaces the other.
- **Discoverable sign-in.** An unauthenticated `GetAuthScheme` RPC lets a client discover how to authenticate before it holds a credential.

## RPCs

The gRPC service name is `orleans.lattice.api.replication`.

| RPC | Kind | Facade operation |
|---|---|---|
| `EnableReplication` | unary | Enable replication for a tree under a fixed merge mode. |
| `DisableReplication` | unary | Disable replication for a tree without purging peer data. |
| `GetReplicationConfig` | unary | Report the permission-scoped per-tree replication config. |
| `GetAuthScheme` | unary (unauthenticated) | Advertise accepted auth schemes. |

### Peer status service

Read-only peer status is a separate service, `orleans.lattice.api.replication.status`,
with one unary RPC, `GetPeerStatus`. It is registered with `AddLatticeReplicationStatusApiGrpc()`
and mapped with `MapLatticeReplicationStatusApiGrpc()`. Call
`AddLatticeReplicationStatusApiGrpc()` after `AddLatticeReplicationApiGrpc()`, whose
authorizer, credential bridge, options and interceptor it reuses - called first, it
throws `InvalidOperationException` - and expose `ILatticeReplicationStatus` in the same
service provider with `AddLatticeReplicationStatusApi()`. It sits behind the same
default-deny interceptor, and `LatticeReplicationApiOperation.GetPeerStatus` names it
for authorizers. `LatticeReplicationStatusGrpcClient` implements
`ILatticeReplicationStatus` directly, so a remote caller uses the same contract as an
in-process one.

## Quick start

Register the binding on a silo that already has `AddLatticeReplicationApi`, then map its routes. The snippet is compiled but not run; [samples/RuntimeReplicationConfig](../../samples/RuntimeReplicationConfig/README.md) is a runnable example of the in-process facade this binding adapts, and does not host the gRPC binding.

```csharp verify
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Orleans.Lattice.Api.Replication.Grpc;

var builder = WebApplication.CreateBuilder();
builder.Services.AddLatticeReplicationApiGrpc(o => o.RequireAuthorization = true);
builder.Services.AddSingleton<ILatticeReplicationApiAuthorizer, AllowAllReplicationApiAuthorizer>();

var app = builder.Build();
app.MapLatticeReplicationApiGrpc();
app.Run();
```

The host must expose the control facade in the same service provider - typically by co-hosting Orleans with `AddLatticeReplication(..., enableRuntimeConfig: true).AddLatticeReplicationApi()` on the same host.

## Client

```csharp verify
using Grpc.Net.Client;
using Orleans.Lattice;
using Orleans.Lattice.Api.Replication.Grpc;

IServiceProvider serializerProvider = CreateSerializerProvider();
static IServiceProvider CreateSerializerProvider()
    => throw new NotImplementedException(
        "Resolve a provider with Orleans serialization registered.");

using var channel = GrpcChannel.ForAddress("https://replication-admin.example:443");
var replicationClient = LatticeReplicationApiGrpcClient.Create(channel.CreateCallInvoker(), serializerProvider);

await replicationClient.EnableReplicationAsync("orders", LatticeMergeMode.OrSet, cancellationToken: cancellationToken);

var report = await replicationClient.GetReplicationConfigAsync(cancellationToken);
foreach (var tree in report.Trees)
{
    // tree.TreeId, tree.Enabled, tree.Mode, tree.Ambiguous, tree.Source
}
```

The `serializerProvider` must have Orleans serialization registered (`AddSerializer()`) so the client and server wire marshallers match exactly. A call the server rejects arrives as a `PermissionDenied` `RpcException`; other failures map to stable status codes (notably `FailedPrecondition` for an in-place mode change or an unmet enable or disable precondition, and `InvalidArgument` for a malformed request). See [Architecture](architecture.md#status-mapping) for the full mapping.

## Reference

- [API reference](api.md) - the public clients, registration entry points, options, authorization seams, and wire message records.
- [Configuration](configuration.md) - the public options properties, their types, and defaults.
- [Architecture](architecture.md) - the two-layer authorization model and the code-first binding.

## See also

- [`Orleans.Lattice.Api.Replication`](../lattice.api.replication/README.md) - the transport-agnostic facade this binding adapts.
- [`Orleans.Lattice.Replication`](../lattice.replication/README.md) - the replication engine underneath.
- [`Orleans.Lattice.Api.Backup.Grpc`](../lattice.api.backup.grpc/README.md) - the sibling gRPC binding this one mirrors.
