DotNET client usage
The .NET client resolves a namespace for every event store operation. You can configure namespace resolution by passing an IEventStoreNamespaceResolver implementation to the ChronicleClient constructor.
IEventStoreNamespaceResolver
public interface IEventStoreNamespaceResolver
{
EventStoreNamespaceName Resolve();
}
The resolver returns the namespace name to use for the current context.
Built-in resolvers
DefaultEventStoreNamespaceResolver
Always returns the default namespace. Use this when you do not need tenant isolation. This is the default when no resolver is supplied.
ClaimsBasedNamespaceResolver
Resolves the namespace from the current principal's claims. This is useful when you have an authenticated user and want to map the tenant from a claim.
// Uses the default claim type "tenant_id"
var client = new ChronicleClient(
options,
namespaceResolver: new ClaimsBasedNamespaceResolver("tenant_id"));
// Uses a custom claim type
var client = new ChronicleClient(
options,
namespaceResolver: new ClaimsBasedNamespaceResolver("custom_tenant_claim"));
If the claim is not found or the user is not authenticated, the default namespace is used.
Passing a resolver to ChronicleClient
For console or direct-client scenarios, pass the resolver as a constructor parameter:
var resolver = new DefaultEventStoreNamespaceResolver();
var client = new ChronicleClient(options, namespaceResolver: resolver);
Configuring in a hosted application
When using IHostApplicationBuilder (worker service or web app), configure the resolver through ChronicleClientOptions or directly via IChronicleBuilder:
// Via options (type is resolved from DI)
builder.AddCratisChronicle(options =>
{
options.EventStore = "my-store";
options.EventStoreNamespaceResolverType = typeof(TenantNamespaceResolver);
});
// Via builder (instance is used directly)
builder.AddCratisChronicle(
configureOptions: options => options.EventStore = "my-store",
configure: b => b.WithNamespaceResolver(new TenantNamespaceResolver(config)));
Custom resolvers
Implement a resolver when your namespace comes from a custom context, such as a tenant provider or a request-scoped service.
If your application uses Arc Tenancy, you can resolve the namespace from its tenant context. See Arc Tenancy.
public class TenantNamespaceResolver : IEventStoreNamespaceResolver
{
readonly ITenantContext _tenantContext;
public TenantNamespaceResolver(ITenantContext tenantContext)
{
_tenantContext = tenantContext;
}
public EventStoreNamespaceName Resolve() =>
_tenantContext.CurrentTenantId;
}
var client = new ChronicleClient(options, namespaceResolver: new TenantNamespaceResolver(tenantContext));
Best practices
- Keep resolvers deterministic within a request or operation
- Provide a safe fallback to the default namespace
- Avoid expensive resolution logic, as it is called frequently
For web applications, see ASP.NET Core namespace resolution.