---
title: "Client"
url: "https://nsta1.github.io/Orleans.Lattice/docs/lattice.api.state/client.html"
source: "https://github.com/NSTA1/Orleans.Lattice/blob/release/9.9/docs/lattice.api.state/client.md"
package: "Orleans.Lattice.Api.State"
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.state/llms-full.txt"
---
# Client

Part of the [Api.State documentation](README.md).

`LatticeStateApiGrpcClient` is the public, strongly-typed client for the state-API gRPC surface. It is the consumer half of the [gRPC contract](grpc-contract.md): one method per RPC, over Orleans-serialized C# request/response records that either reuse facade DTOs directly or wrap facade arguments and results for transport.

## Building a client

`Create` takes a gRPC `CallInvoker` and a service provider that has Orleans serialization registered. The service provider supplies the per-message serializers, so its registration must match the server's (`AddSerializer()`).

```csharp verify
using Grpc.Net.Client;
using Microsoft.Extensions.DependencyInjection;
using Orleans.Serialization;

var serializerProvider = new ServiceCollection().AddSerializer().BuildServiceProvider();

using var channel = GrpcChannel.ForAddress("https://cluster.example:5001");
var stateClient = LatticeStateApiGrpcClient.Create(channel.CreateCallInvoker(), serializerProvider);
```

The client adds **only** the per-RPC marshalling. Address, TLS, retries, deadlines, and call credentials all live on the `GrpcChannel` / `CallInvoker` you pass in, so apply your transport and auth policy there:

```csharp verify
using Grpc.Net.Client;
using Grpc.Core;

var credentials = CallCredentials.FromInterceptor((_, metadata) =>
{
    metadata.Add("authorization", "Bearer <token>");
    return Task.CompletedTask;
});

using var channel = GrpcChannel.ForAddress("https://cluster.example:5001", new GrpcChannelOptions
{
    Credentials = ChannelCredentials.Create(ChannelCredentials.SecureSsl, credentials),
});
```

## Calling the surface

The unary RPCs return a `Task<TResponse>`; the streaming RPCs return an `IAsyncEnumerable<TResponse>` consumed with `await foreach`. The full set, with the request and response each carries, is in [Surfaces](surfaces.md):

- `ListTreesAsync` / `ListViewsAsync` / `ListTagIndexesAsync` / `ListTagValuesAsync` - paged discovery catalog.
- `ListCoveredTreesAsync` / `ListIndexTagsAsync` / `ScanTagMembersAsync` - index-wide tag-index browsing (covered trees, distinct tags, and live tag members across every covered tree).
- `GetTreeStructureAsync` - shard-root node graph.
- `ScanEntriesAsync` / `GetEntryAsync` - key-ordered entry scan (snapshot-isolated by default; `EntryScanMode.Live` / `LivePointInTime` open a cheaper baseline-free cursor) and single-key fetch.
- `GetEntryHistoryAsync` - per-key change-history timeline.
- `CancelScanAsync` - release a server-side scan cursor early.
- `GetDeadLetterCountAsync(DeadLetterCountRequest request, CancellationToken cancellationToken = default)` - count strict-mode dead-letter entries for one tree.
- `ListDeadLettersAsync(DeadLetterQueueRequest request, CancellationToken cancellationToken = default)` - page a tree's strict-mode dead-letter queue.
- `GetMetricsSnapshotAsync` - one-shot metrics.
- `GetClusterInfoAsync` - connected-cluster identity (cluster id, service id).
- `GetAuthSchemeAsync` - the endpoint's advertised auth schemes (unauthenticated; callable before a credential is acquired).
- `ObserveChangesAsync` - server-streamed live mutations.
- `ObserveMetricsAsync` - server-streamed live metric deltas.

Cancel a streaming call through its `CancellationToken` to unsubscribe; the server tears the subscription down when the stream ends.

## In-process reuse

The facade is transport-agnostic, so a consumer co-located in the silo - for example an in-process introspection host - does not need a network hop. The facade interfaces are public in `Orleans.Lattice.Api.Abstractions`, so the simplest path resolves `ILatticeStateQuery` and its observer siblings straight from DI, as the co-hosted `Orleans.Lattice.Api.Mcp` server does. Alternatively, co-host the gRPC service in the silo process (`AddLatticeStateApiGrpc` + `MapLatticeStateApiGrpc`) and dial it over an in-process / loopback channel with the same `LatticeStateApiGrpcClient`: the client code is identical to the remote case; only the channel address changes. The binding's MCP-reuse parity test pins the transport neutrality both paths rely on: a thin adapter over the facade, with no gRPC in between, returns the same records as the gRPC path for the same requests.

The [`StateExplorer`](../../samples/StateExplorer/README.md) sample demonstrates the full journey - silo plus gRPC host in one process, a client dialing it over a loopback channel, and a walk through discovery, structure, scan, and a live change tail.

## Next

- [Surfaces](surfaces.md) - each request and response in detail.
- [Security](security.md) - the channel-side credentials the authorizer validates.
