Skip to content

Structural Dependencies

ChronicleOptions is designed to hold runtime configuration that can be bound from appsettings.json or environment variables — connection strings, timeouts, TLS settings, naming policies, and so on.

Services and providers that must be resolved at registration time (before the DI container is built) are called structural dependencies. These are not configuration values and cannot be meaningfully bound from appsettings.json. They are passed directly as constructor arguments to ChronicleClient or set on IChronicleBuilder when using the DI-hosted setup (IHostApplicationBuilder, WebApplicationBuilder).

DependencyPurposeDefault
IClientArtifactsProviderDiscovers event types, projections, reactors, reducers, and other artifacts at startupDefaultClientArtifactsProvider (auto-discovers from loaded assemblies)
IIdentityProviderSupplies the current user’s identity for event metadataBaseIdentityProvider (empty identity)
ICorrelationIdAccessorProvides the current correlation ID for event metadataCorrelationIdAccessor (generates a new ID per call)
IEventStoreNamespaceResolverResolves the event store namespace for each operationDefaultEventStoreNamespaceResolver (always returns the default namespace)
ILoggerFactoryCreates loggers for the Chronicle client internalsLoggerFactory (no-op)

For console applications or other non-DI scenarios, pass structural dependencies as named constructor parameters:

using Microsoft.Extensions.Logging;
public static class StructuralDependenciesDirectClient
{
public static ChronicleClient Create(ChronicleOptions options, IClientArtifactsProvider myProvider) =>
new(
options,
artifactsProvider: myProvider,
loggerFactory: LoggerFactory.Create(b => b.AddConsole()));
}

All parameters are optional. Any parameter you omit uses the default shown in the table above.

In DI-hosted applications (ASP.NET Core, worker services, or any IHostApplicationBuilder-based host), use the configure callback on AddCratisChronicle to set structural dependencies via the IChronicleBuilder fluent API. This callback runs at registration time, before the DI container is built.

using Cratis.Chronicle.Identities;
using Microsoft.Extensions.Hosting;
public static class StructuralDependenciesChronicleBuilderRegistration
{
public static void Configure(string[] args, IClientArtifactsProvider myCustomProvider, IIdentityProvider myIdentityProvider)
{
var builder = Host.CreateApplicationBuilder(args);
builder.AddCratisChronicle(
configureOptions: options => // runtime config — bindable from appsettings.json
{
options.EventStore = "my-store";
options.ConnectionString = "chronicle://server:35000";
},
configure: b => b // structural dependencies
.WithArtifactsProvider(myCustomProvider)
.WithIdentityProvider(myIdentityProvider));
}
}

The same pattern works with WebApplicationBuilder in ASP.NET Core:

using Cratis.Chronicle.Identities;
using Microsoft.AspNetCore.Builder;
public static class StructuralDependenciesAspNetCoreBuilderRegistration
{
public static void Configure(string[] args, IIdentityProvider myIdentityProvider)
{
// ASP.NET Core — WebApplicationBuilder
var builder = WebApplication.CreateBuilder(args);
builder.AddCratisChronicle(
configureOptions: options => options.EventStore = "my-store",
configure: b => b
.WithIdentityProvider(myIdentityProvider));
}
}

The two callbacks are intentionally separate:

  • configureOptions feeds the options pipeline and can be overridden by appsettings.json or IConfiguration.
  • configure sets structural dependencies at registration time and is not overridable by configuration.
MethodSets
WithArtifactsProvider(IClientArtifactsProvider)Custom artifact discovery
WithIdentityProvider(IIdentityProvider)Custom identity resolution
WithCorrelationIdAccessor(ICorrelationIdAccessor)Custom correlation ID accessor
WithNamespaceResolver(IEventStoreNamespaceResolver)Custom namespace resolution

Implement IClientArtifactsProvider when you need to control exactly which types Chronicle discovers. This is useful in modular applications or when using assembly scanning that differs from the default:

using Cratis.Chronicle.Events;
using Cratis.Chronicle.Projections;
[EventType]
public record StructuralDepsBookBorrowed(string BookId);
[EventType]
public record StructuralDepsBookReturned(string BookId);
public record StructuralDepsBorrowedBook(string BookId);
public class StructuralDepsBorrowedBooksProjection : IProjectionFor<StructuralDepsBorrowedBook>
{
public void Define(IProjectionBuilderFor<StructuralDepsBorrowedBook> builder) => builder
.From<StructuralDepsBookBorrowed>(_ => _.Set(m => m.BookId).To(e => e.BookId));
}
public class StructuralDepsMyArtifactsProvider : IClientArtifactsProvider
{
public IEnumerable<Type> EventTypes => [typeof(StructuralDepsBookBorrowed), typeof(StructuralDepsBookReturned)];
public IEnumerable<Type> Projections => [typeof(StructuralDepsBorrowedBooksProjection)];
public IEnumerable<Type> ModelBoundProjections => [];
public IEnumerable<Type> Reactors => [];
public IEnumerable<Type> Reducers => [];
public IEnumerable<Type> ReactorMiddlewares => [];
public IEnumerable<Type> ComplianceForTypesProviders => [];
public IEnumerable<Type> ComplianceForPropertiesProviders => [];
public IEnumerable<Type> AdditionalEventInformationProviders => [];
public IEnumerable<Type> ConstraintTypes => [];
public IEnumerable<Type> UniqueConstraints => [];
public IEnumerable<Type> UniqueEventTypeConstraints => [];
public IEnumerable<Type> RemoveConstraintEventTypes => [];
public IEnumerable<Type> EventTypeMigrators => [];
public IEnumerable<Type> EventSeeders => [];
}
using Microsoft.Extensions.Hosting;
public static class StructuralDepsCustomArtifactsProviderUsageRegistration
{
public static void Configure(string[] args)
{
var builder = Host.CreateApplicationBuilder(args);
builder.AddCratisChronicle(
configureOptions: options => options.EventStore = "my-store",
configure: b => b.WithArtifactsProvider(new StructuralDepsMyArtifactsProvider()));
}
}

DefaultClientArtifactsProvider scans loaded assemblies for artifacts at first access (lazy initialization). You can construct it with a custom assembly provider:

using Cratis.Types;
public static class StructuralDepsDefaultArtifactsProvider
{
public static DefaultClientArtifactsProvider Create()
{
var assembliesProvider = new CompositeAssemblyProvider(
ProjectReferencedAssemblies.Instance,
PackageReferencedAssemblies.Instance);
return new DefaultClientArtifactsProvider(assembliesProvider);
}
}

The static DefaultClientArtifactsProvider.Default instance is used when no provider is supplied.

Note: DefaultClientArtifactsProvider initializes lazily on first property access; no explicit initialization is required.