CHR0015: Projection must not have side effects
Rule Description
Section titled “Rule Description”A class implementing IProjectionFor<T> must not inject ICommandPipeline or IEventLog via its constructor. Projections are pure state builders that derive read models from events and must not produce side effects.
Severity
Section titled “Severity”Error
Example
Section titled “Example”Violation
Section titled “Violation”using Cratis.Chronicle.Events;using Cratis.Chronicle.EventSequences;using Cratis.Chronicle.Projections;
[EventType]public record Chr0015UserRegistered;
public class Chr0015UserReadModel;
public class Chr0015UserProjection : IProjectionFor<Chr0015UserReadModel>{ readonly IEventLog _eventLog;
// CHR0015: Projections must not take dependencies through the constructor public Chr0015UserProjection(IEventLog eventLog) { _eventLog = eventLog; }
public void Define(IProjectionBuilderFor<Chr0015UserReadModel> builder) => builder.From<Chr0015UserRegistered>();}using Cratis.Chronicle.Events;using Cratis.Chronicle.Projections;
[EventType]public record Chr0015UserRegisteredFixed;
public class Chr0015UserReadModelFixed;
public class Chr0015UserProjectionFixed : IProjectionFor<Chr0015UserReadModelFixed>{ // Now valid - no constructor dependencies public void Define(IProjectionBuilderFor<Chr0015UserReadModelFixed> builder) => builder.From<Chr0015UserRegisteredFixed>();}Why This Rule Exists
Section titled “Why This Rule Exists”Projections declare how to build a read model from a stream of events. They are evaluated at replay time and must be purely declarative. Injecting IEventLog or ICommandPipeline implies intent to perform side effects during projection evaluation, which breaks idempotency and replay safety.