Overview
Savvyio.Extensions.DependencyInjection.EFCore.Domain.EventSourcing registers EF Core backed traced aggregate repositories in Microsoft Dependency Injection. It is the package to use when a traced aggregate root is persisted through Entity Framework Core and exposed through Savvyio's event-sourcing repository abstractions.
It extends Savvyio.Extensions.DependencyInjection.EFCore.Domain with event-sourcing specific registrations and adds the marker-aware EfCoreTracedAggregateRepository<TEntity, TKey, TMarker> implementation on top of Savvyio.Extensions.EFCore.Domain.EventSourcing.
Key APIs
AddEfCoreTracedAggregateRepository<TEntity, TKey>() registers EfCoreTracedAggregateRepository<TEntity, TKey> for traced aggregate roots that implement ITracedAggregateRoot<TKey>. Through AddTracedAggregateRepository, the same registration is type forwarded to ITracedAggregateRepository<TEntity, TKey>, IReadableRepository<TEntity, TKey>, and IWritableRepository<TEntity, TKey>, with the shared ServiceOptions model used elsewhere in the DI packages.
AddEfCoreTracedAggregateRepository<TEntity, TKey, TMarker>() does the same registration work for marker-specific containers. Use this overload when the application distinguishes multiple EF Core data sources or repository implementations by marker type and needs ITracedAggregateRepository<TEntity, TKey, TMarker>, IReadableRepository<TEntity, TKey, TMarker>, and IWritableRepository<TEntity, TKey, TMarker> to resolve to the same implementation.
EfCoreTracedAggregateRepository<TEntity, TKey, TMarker> derives from Savvyio.Extensions.EFCore.Domain.EventSourcing.EfCoreTracedAggregateRepository<TEntity, TKey> and implements ITracedAggregateRepository<TEntity, TKey, TMarker>. Its constructor requires IEfCoreDataSource<TMarker> and IMarshaller, which is the package's bridge between marker-aware DI registration and the lower-level EF Core event-sourcing repository.
Basic usage
using System;
using System.Linq;
using Codebelt.Extensions.Xunit;
using Microsoft.Extensions.DependencyInjection;
using Savvyio;
using Savvyio.Domain.EventSourcing;
using Savvyio.Extensions.DependencyInjection.EFCore;
using Savvyio.Extensions.DependencyInjection.EFCore.Domain.EventSourcing;
using Xunit;
namespace MyProject.Tests;
public class EfCoreTracedAggregateRepositoryRegistrationTest : Test
{
public EfCoreTracedAggregateRepositoryRegistrationTest(ITestOutputHelper output) : base(output) { }
[Fact]
public void AddEfCoreTracedAggregateRepository_ConfiguredMarker_RegistersServices()
{
var services = new ServiceCollection();
services.AddSingleton<IMarshaller, FakeMarshaller>();
services.AddSingleton<IEfCoreDataSource<RepositoryMarker>, FakeEfCoreDataSource>();
services.AddEfCoreTracedAggregateRepository<BankAccount, Guid, RepositoryMarker>();
TestOutput.WriteLine($"Registered services: {services.Count}");
Assert.Contains(services, d => d.ServiceType.Name.Contains("ITracedAggregateRepository"));
Assert.Contains(services, d => d.ServiceType.Name.Contains("IReadableRepository"));
Assert.Contains(services, d => d.ServiceType.Name.Contains("IWritableRepository"));
}
}
public sealed class BankAccount : TracedAggregateRoot<Guid>
{
protected override void RegisterDelegates(Savvyio.Handlers.IFireForgetRegistry<ITracedDomainEvent> handler) { }
}
public sealed class RepositoryMarker { }
public sealed class FakeEfCoreDataSource : IEfCoreDataSource<RepositoryMarker>
{
public Microsoft.EntityFrameworkCore.DbSet<TEntity> Set<TEntity>() where TEntity : class => throw new NotSupportedException();
public System.Threading.Tasks.Task SaveChangesAsync(Action<Cuemon.Threading.AsyncOptions>? setup = null) => System.Threading.Tasks.Task.CompletedTask;
}
public sealed class FakeMarshaller : IMarshaller
{
public System.IO.Stream Serialize<TValue>(TValue value) => System.IO.Stream.Null;
public System.IO.Stream Serialize(object value, Type inputType) => System.IO.Stream.Null;
public TValue Deserialize<TValue>(System.IO.Stream data) => throw new NotSupportedException();
public object Deserialize(System.IO.Stream data, Type returnType) => throw new NotSupportedException();
}
Use this pattern when you need the marker-specific overload registered before the container is built. It matters because the package adds the traced, readable, and writable repository service descriptors in one call.
Installation
dotnet add package Savvyio.Extensions.DependencyInjection.EFCore.Domain.EventSourcing
Usage guidance
Adopt this package when EF Core is your persistence boundary for traced aggregates and you want DI registrations that expose the same repository implementation through the traced, readable, and writable repository abstractions, with an optional marker-specific overload when the container hosts multiple implementations. If you only need aggregate repositories without event sourcing, Savvyio.Extensions.DependencyInjection.EFCore.Domain is the smaller fit, and if you do not need DI-specific registrations, the lower-level Savvyio.Extensions.EFCore.Domain.EventSourcing package is the better entry point.
Family packages
- 🏭Savvyio.App
- 📦Savvyio.Commands
- 📦Savvyio.Commands.Messaging
- 📦Savvyio.Core
- 📦Savvyio.Domain
- 📦Savvyio.Domain.EventSourcing
- 📦Savvyio.EventDriven
- 📦Savvyio.EventDriven.Messaging
- 📦Savvyio.Extensions.Dapper
- 📦Savvyio.Extensions.DapperExtensions
- 📦Savvyio.Extensions.DependencyInjection
- 📦Savvyio.Extensions.DependencyInjection.Dapper
- 📦Savvyio.Extensions.DependencyInjection.DapperExtensions
- 📦Savvyio.Extensions.DependencyInjection.Domain
- 📦Savvyio.Extensions.DependencyInjection.EFCore
- 📦Savvyio.Extensions.DependencyInjection.EFCore.Domain
- 📦Savvyio.Extensions.DependencyInjection.NATS
- 📝Savvyio.Extensions.DependencyInjection.Newtonsoft.Json
- 📦Savvyio.Extensions.DependencyInjection.QueueStorage
- 📦Savvyio.Extensions.DependencyInjection.RabbitMQ
- 📦Savvyio.Extensions.DependencyInjection.SimpleQueueService
- 📝Savvyio.Extensions.DependencyInjection.Text.Json
- 📦Savvyio.Extensions.Dispatchers
- 📦Savvyio.Extensions.EFCore
- 📦Savvyio.Extensions.EFCore.Domain
- 📦Savvyio.Extensions.EFCore.Domain.EventSourcing
- 📦Savvyio.Extensions.NATS
- 📝Savvyio.Extensions.Newtonsoft.Json
- 📦Savvyio.Extensions.QueueStorage
- 📦Savvyio.Extensions.RabbitMQ
- 📦Savvyio.Extensions.SimpleQueueService
- 📝Savvyio.Extensions.Text.Json
- 📦Savvyio.Messaging
- 📦Savvyio.Queries