C# Reference
The SpacetimeDB client for C# contains all the tools you need to build native clients for SpacetimeDB modules using C#.
Server module quick reference
If you are writing a SpacetimeDB module (tables and reducers), use these patterns:
- Module class:
public static partial class Module - Tables:
[SpacetimeDB.Table(Accessor = "table_name", Public = true)]onpartial struct(orpartial class) —Accessorcontrols generated API names, and canonical SQL names are derived unlessNameis explicitly set - Primary key: Define
[SpacetimeDB.PrimaryKey]on one column when you need key-based lookups or updates - Reducers:
[SpacetimeDB.Reducer]on static methods withReducerContext ctxas first parameter - Required:
using SpacetimeDB;andpartialon all table structs and the Module class - Index: Always use
SpacetimeDB.Index.BTree(never bareIndex). BareIndexis ambiguous withSystem.Index. For multi-column:Columns = new[] { nameof(Col1), nameof(Col2) }, not collection expressions[nameof(X)] - Sum types: Use
TaggedEnum<(VariantA A, VariantB B)>withpartial record, notpartial class - Scheduled tables:
ScheduledAtshould reference a field of typeScheduleAtin the schedule table
See Tables, Reducers, and Column Types for full server-side documentation. The rest of this page covers the client SDK (connections, subscriptions, callbacks).
Before diving into the reference, you may want to review:
- Generating Client Bindings - How to generate C# bindings from your module
- Connecting to SpacetimeDB - Establishing and managing connections (important: C# requires manual connection advancement!)
- SDK API Reference - Core concepts that apply across all SDKs
| Name | Description |
|---|---|
| Project setup | Configure a C# project to use the SpacetimeDB C# client SDK. |
| Generate module bindings | Use the SpacetimeDB CLI to generate module-specific types and interfaces. |
DbConnection type | A connection to a remote database. |
IDbContext interface | Methods for interacting with the remote database. |
EventContext type | Implements IDbContext for row callbacks. |
ReducerEventContext type | Implements IDbContext for reducer callbacks. |
SubscriptionEventContext type | Implements IDbContext for subscription callbacks. |
ErrorContext type | Implements IDbContext for error-related callbacks. |
| Query Builder API | Type-safe query builder for typed subscription queries. |
| Access the client cache | Access to your local view of the database. |
| Observe and invoke reducers | Send requests to the database to run reducers, and register callbacks to run when notified of reducers. |
| Identify a client | Types for identifying users and client connections. |
Project setup
Using the dotnet CLI tool
If you would like to create a console application using .NET, you can create a new project using dotnet new console and add the SpacetimeDB SDK to your dependencies:
dotnet add package SpacetimeDB.ClientSDK
(See also the CSharp Quickstart for an in-depth example of such a console application.)
Using Unity
Add the SpacetimeDB Unity Package using the Package Manager. Open the Package Manager window by clicking on Window -> Package Manager. Click on the + button in the top left corner of the window and select "Add package from git URL". Enter the following URL and click Add.
https://github.com/clockworklabs/com.clockworklabs.spacetimedbsdk.git
(See also the Unity Tutorial)
Generate module bindings
Each SpacetimeDB client depends on some bindings specific to your module. Create a module_bindings directory in your project's directory and generate the C# interface files using the Spacetime CLI. From your project directory, run:
mkdir -p module_bindings
spacetime generate --lang cs --out-dir module_bindings --module-path PATH-TO-MODULE-DIRECTORY
Replace PATH-TO-MODULE-DIRECTORY with the path to your SpacetimeDB module.
Type DbConnection
A connection to a remote database is represented by the DbConnection class. This class is generated per module and contains information about the types, tables, and reducers defined by your module.
| Name | Description |
|---|---|
| Connect to a database | Construct a DbConnection instance. |
| Advance the connection | Poll the DbConnection or run it in the background. |
| Access tables and reducers | Access the client cache, request reducer invocations, and register callbacks. |
Connect to a database
class DbConnection
{
public static DbConnectionBuilder<DbConnection> Builder();
}
Construct a DbConnection by calling DbConnection.Builder(), chaining configuration methods, and finally calling .Build(). At a minimum, you must specify WithUri to provide the URI of the SpacetimeDB instance, and WithDatabaseName to specify the database's name or identity.
| Name | Description |
|---|---|
| WithUri method | Set the URI of the SpacetimeDB instance hosting the remote database. |
| WithDatabaseName method | Set the name or identity of the remote database. |
| WithConfirmedReads method | Enable or disable confirmed reads. |
| OnConnect callback | Register a callback to run when the connection is successfully established. |
| OnConnectError callback | Register a callback to run if the connection is rejected or the host is unreachable. |
| OnDisconnect callback | Register a callback to run when the connection ends. |
| WithToken method | Supply a token to authenticate with the remote database. |
| Build method | Finalize configuration and open the connection. |
Method WithUri
class DbConnectionBuilder<DbConnection>
{
public DbConnectionBuilder<DbConnection> WithUri(Uri uri);
}
Configure the URI of the SpacetimeDB instance or cluster which hosts the remote module and database.
Method WithDatabaseName
class DbConnectionBuilder
{
public DbConnectionBuilder<DbConnection> WithDatabaseName(string nameOrIdentity);
}
Configure the SpacetimeDB domain name or Identity of the remote database which identifies it within the SpacetimeDB instance or cluster.
Method WithConfirmedReads
class DbConnectionBuilder
{
public DbConnectionBuilder<DbConnection> WithConfirmedReads(bool confirmedReads);
}
Configure the connection to request confirmed reads.
When enabled, the server will send query results only after they are confirmed to be durable, i.e. persisted to disk on one or more replicas depending on the replication settings of the database. When set to false, the server will send results as soon as transactions are committed in memory.
If this method is not called, the server chooses the default.
Callback OnConnect
class DbConnectionBuilder<DbConnection>
{
public DbConnectionBuilder<DbConnection> OnConnect(Action<DbConnection, Identity, string> callback);
}
Chain a call to .OnConnect(callback) to your builder to register a callback to run when your new DbConnection successfully initiates its connection to the remote database. The callback accepts three arguments: a reference to the DbConnection, the Identity by which SpacetimeDB identifies this connection, and a private access token which can be saved and later passed to WithToken to authenticate the same user in future connections.
Callback OnConnectError
class DbConnectionBuilder<DbConnection>
{
public DbConnectionBuilder<DbConnection> OnConnectError(Action<ErrorContext, SpacetimeDbException> callback);
}
Chain a call to .OnConnectError(callback) to your builder to register a callback to run when your connection fails.
A known bug in the SpacetimeDB Rust client SDK currently causes this callback never to be invoked. OnDisconnect callbacks are invoked instead.
Callback OnDisconnect
class DbConnectionBuilder<DbConnection>
{
public DbConnectionBuilder<DbConnection> OnDisconnect(Action<ErrorContext, SpacetimeDbException> callback);
}
Chain a call to .OnDisconnect(callback) to your builder to register a callback to run when your DbConnection disconnects from the remote database, either as a result of a call to Disconnect or due to an error.
Method WithToken
class DbConnectionBuilder<DbConnection>
{
public DbConnectionBuilder<DbConnection> WithToken(string token = null);
}
Chain a call to .WithToken(token) to your builder to provide an OpenID Connect compliant JSON Web Token to authenticate with, or to explicitly select an anonymous connection. If this method is not called or None is passed, SpacetimeDB will generate a new Identity and sign a new private access token for the connection.
Method Build
class DbConnectionBuilder<DbConnection>
{
public DbConnection Build();
}
After configuring the connection and registering callbacks, attempt to open the connection.
Advance the connection and process messages
In the interest of supporting a wide variety of client applications with different execution strategies, the SpacetimeDB SDK allows you to choose when the DbConnection spends compute time and processes messages. If you do not arrange for the connection to advance by calling one of these methods, the DbConnection will never advance, and no callbacks will ever be invoked.
| Name | Description |
|---|---|
FrameTick method | Process messages on the main thread without blocking. |
Method FrameTick
class DbConnection {
public void FrameTick();
}
FrameTick will advance the connection until no work remains or until it is disconnected, then return rather than blocking. Games might arrange for this message to be called every frame.
It is not advised to run FrameTick on a background thread, since it modifies dbConnection.Db. If main thread code is also accessing the Db, it may observe data races when FrameTick runs on another thread.
(Note that the SDK already does most of the work for parsing messages on a background thread. FrameTick() does the minimal amount of work needed to apply updates to the Db.)
Access tables and reducers
Property Db
class DbConnection
{
public RemoteTables Db;
/* other members */
}
The Db property of the DbConnection provides access to the subscribed view of the remote database's tables. See Access the client cache.
Property Reducers
class DbConnection
{
public RemoteReducers Reducers;
/* other members */
}
The Reducers field of the DbConnection provides access to reducers exposed by the module of the remote database. See Observe and invoke reducers.
Interface IDbContext
interface IDbContext<DbView, RemoteReducers, ..>
{
/* methods */
}
DbConnection, EventContext, ReducerEventContext, SubscriptionEventContext and ErrorContext all implement IDbContext. IDbContext has methods for inspecting and configuring your connection to the remote database.
The IDbContext interface is implemented by connections and contexts to every module - hence why it takes DbView and RemoteReducers as type parameters.
| Name | Description |
|---|---|
IRemoteDbContext interface | Module-specific IDbContext. |
Db method | Provides access to the subscribed view of the remote database's tables. |
Reducers method | Provides access to reducers exposed by the remote module. |
Disconnect method | End the connection. |
| Subscribe to queries | Register subscription queries to receive updates about matching rows. |
| Read connection metadata | Access the connection's Identity and ConnectionId |
Interface IRemoteDbContext
Each module's module_bindings exports an interface IRemoteDbContext which inherits from IDbContext, with the type parameters DbView and RemoteReducers bound to the types defined for that module. This can be more convenient when creating functions that can be called from any callback for a specific module, but which access the database or invoke reducers, and so must know the type of the DbView or Reducers.
Method Db
interface IRemoteDbContext
{
public DbView Db { get; }
}
Db will have methods to access each table defined by the module.
Example
var conn = ConnectToDB();
// Get a handle to the User table
var tableHandle = conn.Db.User;
Method Reducers
interface IRemoteDbContext
{
public RemoteReducers Reducers { get; }
}
Reducers will have methods to invoke each reducer defined by the module,
plus methods for adding and removing callbacks on each of those reducers.
Example
var conn = ConnectToDB();
// Register a callback to be run every time the SendMessage reducer is invoked
conn.Reducers.OnSendMessage += Reducer_OnSendMessageEvent;
Method Disconnect
interface IRemoteDbContext
{
public void Disconnect();
}
Gracefully close the DbConnection. Throws an error if the connection is already closed.
Subscribe to queries
| Name | Description |
|---|---|
SubscriptionBuilder type | Builder-pattern constructor to register subscribed queries. |
TypedSubscriptionBuilder type | Builder for typed query subscriptions. |
SubscriptionHandle type | Manage an active subscription. |
Type SubscriptionBuilder
| Name | Description |
|---|---|
ctx.SubscriptionBuilder() constructor | Begin configuring a new subscription. |
OnApplied callback | Register a callback to run when matching rows become available. |
OnError callback | Register a callback to run if the subscription fails. |
Subscribe method | Finish configuration and subscribe to one or more queries. |
AddQuery method | Build a typed subscription query without writing query strings. |
SubscribeToAllTables method | Convenience method to subscribe to the entire database. |
Constructor ctx.SubscriptionBuilder()
interface IRemoteDbContext
{
public SubscriptionBuilder SubscriptionBuilder();
}
Subscribe to queries by calling ctx.SubscriptionBuilder() and chaining configuration methods, then calling .Subscribe(queries).
Callback OnApplied
class SubscriptionBuilder
{
public SubscriptionBuilder OnApplied(Action<SubscriptionEventContext> callback);
}
Register a callback to run when the subscription is applied and the matching rows are inserted into the client cache.
Callback OnError
class SubscriptionBuilder
{
public SubscriptionBuilder OnError(Action<ErrorContext, Exception> callback);
}
Register a callback to run if the subscription is rejected or unexpectedly terminated by the server. This is most frequently caused by passing an invalid query to Subscribe.
Method Subscribe
class SubscriptionBuilder
{
public SubscriptionHandle Subscribe(string[] querySqls);
}
Subscribe to a set of queries. queries should be an array of SQL query strings.
See the SpacetimeDB SQL Reference for information on the queries SpacetimeDB supports as subscriptions.
For typed query subscriptions, use AddQuery.
Method AddQuery
class SubscriptionBuilder
{
public TypedSubscriptionBuilder AddQuery<TRow>(
Func<QueryBuilder, IQuery<TRow>> build
);
}
Start a typed query subscription. Once a typed query is added, continue with typed queries on TypedSubscriptionBuilder and finish with Subscribe().
var handle = conn
.SubscriptionBuilder()
.AddQuery(q => q.From.User())
.AddQuery(q => q.From.Message())
.Subscribe();
Method SubscribeToAllTables
class SubscriptionBuilder
{
public void SubscribeToAllTables();
}
Subscribe to all rows from all public tables. This method is provided as a convenience for simple clients. The subscription initiated by SubscribeToAllTables cannot be canceled after it is initiated. You should subscribe to specific queries if you need fine-grained control over the lifecycle of your subscriptions.
Type TypedSubscriptionBuilder
| Name | Description |
|---|---|
AddQuery method | Add another typed query to the same subscription. |
Subscribe method | Subscribe to all typed queries added so far. |