Skip to content

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.

using Cratis.Chronicle;
public class NamespacesDotNetClientSampleResolver : IEventStoreNamespaceResolver
{
public EventStoreNamespaceName Resolve() => EventStoreNamespaceName.Default;
}

View C# snippet source on GitHub

The resolver returns the namespace name to use for the current context.

Always returns the default namespace. Use this when you do not need tenant isolation. This is the default when no resolver is supplied.

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.

using Cratis.Chronicle;
public static class NamespacesDotNetClientClaimsBased
{
public static ChronicleClient CreateWithDefaultClaimType(ChronicleOptions options) =>
// Uses the default claim type "tenant_id"
new(options, namespaceResolver: new ClaimsBasedNamespaceResolver("tenant_id"));
public static ChronicleClient CreateWithCustomClaimType(ChronicleOptions options) =>
// Uses a custom claim type
new(options, namespaceResolver: new ClaimsBasedNamespaceResolver("custom_tenant_claim"));
}

View C# snippet source on GitHub

If the claim is not found or the user is not authenticated, the default namespace is used.

For console or direct-client scenarios, pass the resolver as a constructor parameter:

using Cratis.Chronicle;
public static class NamespacesDotNetClientDefaultResolver
{
public static ChronicleClient Create(ChronicleOptions options)
{
var resolver = new DefaultEventStoreNamespaceResolver();
return new ChronicleClient(options, namespaceResolver: resolver);
}
}

View C# snippet source on GitHub

When using IHostApplicationBuilder (worker service or web app), configure the resolver through ChronicleClientOptions or directly via IChronicleBuilder:

using Microsoft.Extensions.Hosting;
public static class NamespacesDotNetClientHostedAppConfiguration
{
public static void ConfigureViaOptions(IHostApplicationBuilder builder) =>
// Via options (type is resolved from DI)
builder.AddCratisChronicle(options =>
{
options.EventStore = "my-store";
options.EventStoreNamespaceResolverType = typeof(TenantNamespaceResolver);
});
public static void ConfigureViaBuilder(IHostApplicationBuilder builder, ITenantContext tenantContext) =>
// Via builder (instance is used directly)
builder.AddCratisChronicle(
configureOptions: options => options.EventStore = "my-store",
configure: b => b.WithNamespaceResolver(new TenantNamespaceResolver(tenantContext)));
}

View C# snippet source on GitHub

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.

using Cratis.Chronicle;
public interface ITenantContext
{
EventStoreNamespaceName CurrentTenantId { get; }
}
public class TenantNamespaceResolver : IEventStoreNamespaceResolver
{
readonly ITenantContext _tenantContext;
public TenantNamespaceResolver(ITenantContext tenantContext)
{
_tenantContext = tenantContext;
}
public EventStoreNamespaceName Resolve() =>
_tenantContext.CurrentTenantId;
}

View C# snippet source on GitHub

using Cratis.Chronicle;
public static class NamespacesDotNetClientTenantResolverUsage
{
public static ChronicleClient Create(ChronicleOptions options, ITenantContext tenantContext) =>
new(options, namespaceResolver: new TenantNamespaceResolver(tenantContext));
}

View C# snippet source on GitHub

  • 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.