dotnet-cqrs/Svrnty.CQRS.Events.Abstractions/Models/CommandResultWithEvents.cs

188 lines
6.1 KiB
C#

using System;
using Svrnty.CQRS.Events.Abstractions.EventStore;
using System.Collections.Generic;
using System.Linq;
namespace Svrnty.CQRS.Events.Abstractions.Models;
/// <summary>
/// Wraps a command result with events to be emitted.
/// The framework automatically handles correlation ID assignment and event emission.
/// </summary>
/// <typeparam name="TResult">The type of the command result.</typeparam>
public sealed class CommandResultWithEvents<TResult>
{
private readonly List<ICorrelatedEvent> _events = new();
/// <summary>
/// The result of the command execution.
/// </summary>
public TResult Result { get; }
/// <summary>
/// Events to be emitted with automatic correlation ID management.
/// </summary>
public IReadOnlyList<ICorrelatedEvent> Events => _events.AsReadOnly();
/// <summary>
/// Correlation ID assigned by the framework.
/// Available after the command is processed.
/// This setter is public for framework use but should not be set by application code.
/// </summary>
public string? CorrelationId { get; set; }
public CommandResultWithEvents(TResult result)
{
Result = result;
}
public CommandResultWithEvents(TResult result, params ICorrelatedEvent[] events)
{
Result = result;
_events.AddRange(events);
}
public CommandResultWithEvents(TResult result, IEnumerable<ICorrelatedEvent> events)
{
Result = result;
_events.AddRange(events);
}
/// <summary>
/// Add an event to be emitted. The correlation ID will be automatically assigned.
/// </summary>
public CommandResultWithEvents<TResult> AddEvent(ICorrelatedEvent @event)
{
_events.Add(@event);
return this;
}
/// <summary>
/// Add multiple events to be emitted. Correlation IDs will be automatically assigned.
/// </summary>
public CommandResultWithEvents<TResult> AddEvents(params ICorrelatedEvent[] events)
{
_events.AddRange(events);
return this;
}
/// <summary>
/// Add multiple events to be emitted. Correlation IDs will be automatically assigned.
/// </summary>
public CommandResultWithEvents<TResult> AddEvents(IEnumerable<ICorrelatedEvent> events)
{
_events.AddRange(events);
return this;
}
/// <summary>
/// Method used by the framework to assign correlation IDs to all events.
/// This method is public for framework use but should not be called by application code.
/// </summary>
public void AssignCorrelationIds(string correlationId)
{
CorrelationId = correlationId;
foreach (var @event in _events)
{
// Use reflection to set the correlation ID
var correlationIdProperty = @event.GetType().GetProperty(nameof(ICorrelatedEvent.CorrelationId));
if (correlationIdProperty != null && correlationIdProperty.CanWrite)
{
correlationIdProperty.SetValue(@event, correlationId);
}
else if (correlationIdProperty != null && correlationIdProperty.GetSetMethod(nonPublic: true) != null)
{
// Handle init-only properties
correlationIdProperty.GetSetMethod(nonPublic: true)!.Invoke(@event, new object[] { correlationId });
}
}
}
}
/// <summary>
/// Wraps events to be emitted for commands that don't return a result.
/// The framework automatically handles correlation ID assignment and event emission.
/// </summary>
public sealed class CommandResultWithEvents
{
private readonly List<ICorrelatedEvent> _events = new();
/// <summary>
/// Events to be emitted with automatic correlation ID management.
/// </summary>
public IReadOnlyList<ICorrelatedEvent> Events => _events.AsReadOnly();
/// <summary>
/// Correlation ID assigned by the framework.
/// Available after the command is processed.
/// This setter is public for framework use but should not be set by application code.
/// </summary>
public string? CorrelationId { get; set; }
public CommandResultWithEvents()
{
}
public CommandResultWithEvents(params ICorrelatedEvent[] events)
{
_events.AddRange(events);
}
public CommandResultWithEvents(IEnumerable<ICorrelatedEvent> events)
{
_events.AddRange(events);
}
/// <summary>
/// Add an event to be emitted. The correlation ID will be automatically assigned.
/// </summary>
public CommandResultWithEvents AddEvent(ICorrelatedEvent @event)
{
_events.Add(@event);
return this;
}
/// <summary>
/// Add multiple events to be emitted. Correlation IDs will be automatically assigned.
/// </summary>
public CommandResultWithEvents AddEvents(params ICorrelatedEvent[] events)
{
_events.AddRange(events);
return this;
}
/// <summary>
/// Add multiple events to be emitted. Correlation IDs will be automatically assigned.
/// </summary>
public CommandResultWithEvents AddEvents(IEnumerable<ICorrelatedEvent> events)
{
_events.AddRange(events);
return this;
}
/// <summary>
/// Method used by the framework to assign correlation IDs to all events.
/// This method is public for framework use but should not be called by application code.
/// </summary>
public void AssignCorrelationIds(string correlationId)
{
CorrelationId = correlationId;
foreach (var @event in _events)
{
// Use reflection to set the correlation ID
var correlationIdProperty = @event.GetType().GetProperty(nameof(ICorrelatedEvent.CorrelationId));
if (correlationIdProperty != null && correlationIdProperty.CanWrite)
{
correlationIdProperty.SetValue(@event, correlationId);
}
else if (correlationIdProperty != null && correlationIdProperty.GetSetMethod(nonPublic: true) != null)
{
// Handle init-only properties
correlationIdProperty.GetSetMethod(nonPublic: true)!.Invoke(@event, new object[] { correlationId });
}
}
}
}