Camel Casing
Chronicle can apply a camel case naming policy when building projection definitions and persisting read models. This keeps property names consistent with common JSON naming conventions.
Overview
Section titled “Overview”By default, Chronicle uses property names as they appear in C# (PascalCase). Enabling camel case will:
- Govern how projection definitions are built
- Determine the property names used when projections update read models
- Keep naming consistent across projection and read model data
Using a Direct Client
Section titled “Using a Direct Client”For direct ChronicleClient usage outside of a hosted application, pass a CamelCaseNamingPolicy instance via the named namingPolicy constructor argument:
using Cratis.Chronicle;using Cratis.Serialization;
public static class CamelCasingDirectClient{ public static ChronicleClient Create() => new(options: new ChronicleOptions(), namingPolicy: new CamelCaseNamingPolicy());}Kotlin does not support this workflow yet.Java does not support this workflow yet.Elixir does not support this workflow yet.TypeScript does not support this workflow yet.Using ASP.NET Core
Section titled “Using ASP.NET Core”When building ASP.NET Core applications, use the dependency injection extensions to configure Chronicle with camel case naming policy.
Basic Configuration
Section titled “Basic Configuration”In your Program.cs file, configure Chronicle with camel case naming policy using the IChronicleBuilder callback:
using Microsoft.AspNetCore.Builder;
public static class CamelCasingAspNetCoreBasicRegistration{ public static void Configure(string[] args) { var builder = WebApplication.CreateBuilder(args);
builder.AddCratisChronicle( configure: chronicleBuilder => chronicleBuilder.WithCamelCaseNamingPolicy());
var app = builder.Build(); }}Kotlin does not support this workflow yet.Java does not support this workflow yet.Elixir does not support this workflow yet.TypeScript does not support this workflow yet.Dependency Injection Configuration
Section titled “Dependency Injection Configuration”You can combine camel case naming policy with other Chronicle configuration options:
using Microsoft.AspNetCore.Builder;
public static class CamelCasingAspNetCoreWithOptionsRegistration{ public static void Configure(string[] args) { var builder = WebApplication.CreateBuilder(args);
builder.AddCratisChronicle( configureOptions: options => options.EventStore = "MyEventStore", configure: chronicleBuilder => chronicleBuilder.WithCamelCaseNamingPolicy());
var app = builder.Build(); }}Kotlin does not support this workflow yet.Java does not support this workflow yet.Elixir does not support this workflow yet.TypeScript does not support this workflow yet.Using .NET Host (Worker Services)
Section titled “Using .NET Host (Worker Services)”For worker services or other non-web hosts using IHostApplicationBuilder:
using Microsoft.Extensions.Hosting;
public static class CamelCasingWorkerHostRegistration{ public static void Configure(string[] args) { var builder = Host.CreateApplicationBuilder(args);
builder.AddCratisChronicle( configure: chronicleBuilder => chronicleBuilder.WithCamelCaseNamingPolicy());
var host = builder.Build(); }}Kotlin does not support this workflow yet.Java does not support this workflow yet.Elixir does not support this workflow yet.TypeScript does not support this workflow yet.Impact on Projections
Section titled “Impact on Projections”The naming policy configuration affects how Chronicle handles projections:
Projection Definition Building
Section titled “Projection Definition Building”When you configure camel case naming policy, Chronicle uses this policy when building projection definitions. This means property mappings within projections will use camel case property names.
Read Models
Section titled “Read Models”The naming policy affects the read model container name, which affects the name of the collection, table, or file that data is persisted as.
When projections project to read models, the property names used will follow the configured naming policy. For example:
Event Definition
Section titled “Event Definition”using Cratis.Chronicle.Events;
[EventType]public record CamelCasingUserRegistered( string FirstName, string LastName, string EmailAddress, DateTime RegistrationDate);import io.cratis.chronicle.events.EventTypeimport java.time.Instant
@EventTypedata class CamelCasingUserRegistered( val firstName: String = "", val lastName: String = "", val emailAddress: String = "", val registrationDate: Instant = Instant.EPOCH)import io.cratis.chronicle.events.EventType;
import java.time.Instant;
@EventTyperecord CamelCasingUserRegistered( String firstName, String lastName, String emailAddress, Instant registrationDate) {}defmodule MyApp.Events.CamelCasingUserRegistered do use Chronicle.Events.EventType, id: "camel-casing-user-registered"
defstruct [:first_name, :last_name, :email_address, :registration_date]endTypeScript does not support this workflow yet.Read Model Definition
Section titled “Read Model Definition”public class CamelCasingUserReadModel{ public string FirstName { get; set; } = string.Empty; public string LastName { get; set; } = string.Empty; public string EmailAddress { get; set; } = string.Empty; public DateTime RegistrationDate { get; set; }}import io.cratis.chronicle.readModels.ReadModelimport java.time.Instant
@ReadModeldata class CamelCasingUserReadModel( val firstName: String = "", val lastName: String = "", val emailAddress: String = "", val registrationDate: Instant = Instant.EPOCH)import io.cratis.chronicle.readModels.ReadModel;
import java.time.Instant;
@ReadModelclass CamelCasingUserReadModel { public String firstName = ""; public String lastName = ""; public String emailAddress = ""; public Instant registrationDate = Instant.EPOCH;}defmodule MyApp.ReadModels.CamelCasingUser do use Chronicle.ReadModels.ReadModel
defstruct first_name: nil, last_name: nil, email_address: nil, registration_date: nilendTypeScript does not support this workflow yet.Projection with Camel Case Naming Policy
Section titled “Projection with Camel Case Naming Policy”With camel case naming policy configured, Chronicle will use camel case property names when building the projection:
using Cratis.Chronicle.Projections;
public class CamelCasingUserProjection : IProjectionFor<CamelCasingUserReadModel>{ public void Define(IProjectionBuilderFor<CamelCasingUserReadModel> builder) => builder .From<CamelCasingUserRegistered>(_ => _ .Set(m => m.FirstName).To(e => e.FirstName) .Set(m => m.LastName).To(e => e.LastName) .Set(m => m.EmailAddress).To(e => e.EmailAddress) .Set(m => m.RegistrationDate).To(e => e.RegistrationDate));}import io.cratis.chronicle.projections.IProjectionForimport io.cratis.chronicle.projections.IProjectionBuilderFor
// Kotlin property names are already camelCase, so the projected read model properties below —// firstName, lastName, emailAddress, registrationDate — need no naming policy configuration to// come out as camelCase; that is simply how Kotlin properties are named.class CamelCasingUserProjection : IProjectionFor<CamelCasingUserReadModel> { override fun define(builder: IProjectionBuilderFor<CamelCasingUserReadModel>) { builder.from(CamelCasingUserRegistered::class) { it.set(CamelCasingUserReadModel::firstName).to { e -> e.firstName } it.set(CamelCasingUserReadModel::lastName).to { e -> e.lastName } it.set(CamelCasingUserReadModel::emailAddress).to { e -> e.emailAddress } it.set(CamelCasingUserReadModel::registrationDate).to { e -> e.registrationDate } } }}import io.cratis.chronicle.projections.IProjectionFor;import io.cratis.chronicle.projections.IProjectionBuilderFor;import io.cratis.chronicle.java.ProjectionBuilderJavaBridge;
// Java field names are already camelCase, and AutoMap matches read model properties to event// properties of the same name — firstName, lastName, emailAddress, registrationDate — so no// naming policy configuration is needed to have them come out as camelCase.class CamelCasingUserProjection implements IProjectionFor<CamelCasingUserReadModel> { @Override public void define(IProjectionBuilderFor<CamelCasingUserReadModel> builder) { ProjectionBuilderJavaBridge.from(builder, CamelCasingUserRegistered.class); }}defmodule MyApp.Projections.CamelCasingUserProjection do use Chronicle.Projections.Projection, model: MyApp.ReadModels.CamelCasingUser
from MyApp.Events.CamelCasingUserRegistered, set: [ first_name: :first_name, last_name: :last_name, email_address: :email_address, registration_date: :registration_date ]endTypeScript does not support this workflow yet.The resulting read model data will have camel case property names: firstName, lastName, emailAddress, registrationDate.
Important Notes
Section titled “Important Notes”- The naming policy affects how Chronicle builds projection definitions internally.
- Property names in read models will follow the configured naming policy when data is persisted.
- This configuration is specific to Chronicle operations and does not affect general ASP.NET Core JSON serialization.
- All projections in your application will use the same naming policy once configured.
Troubleshooting
Section titled “Troubleshooting”Projection Property Names Not Converting
Section titled “Projection Property Names Not Converting”If projection property names are not being converted to camel case:
- Verify that
WithCamelCaseNamingPolicy()is called on theIChronicleBuilderduring Chronicle configuration. - Ensure the configuration is applied before Chronicle services are initialized.
- Check that all projections are using the same Chronicle client instance.
Inconsistent Property Naming
Section titled “Inconsistent Property Naming”If you see inconsistent property naming in your read models:
- Verify that Chronicle is configured with the camel case naming policy via
IChronicleBuilder.WithCamelCaseNamingPolicy(). - Check if any custom property mappings are overriding the global naming policy.
- Ensure all projection definitions are rebuilt after changing the naming policy.