Codebelt

Savvyio.Extensions.DependencyInjection.EFCore.Domain

Add aggregate-aware EF Core data sources and repositories to DI while keeping Savvy I/O domain event dispatch and marker-based resolution intact.

.NET 10.0 / .NET 9.0 MIT v5.0.8 11,193 downloads

Overview

Savvyio.Extensions.DependencyInjection.EFCore.Domain adds Microsoft Dependency Injection registration support for EF Core-backed aggregate data sources and aggregate repositories in Savvy I/O. It builds on the aggregate-aware EF Core behavior from Savvyio.Extensions.EFCore.Domain and the DI registration model from Savvyio.Extensions.DependencyInjection.EFCore, so aggregate roots can be resolved through default or marker-specific contracts.

The package is focused on composition and type forwarding. Its public surface registers aggregate-aware EF Core data sources as IEfCoreDataSource, IDataSource, and IUnitOfWork, and registers EF Core aggregate repositories through the aggregate, persistent, readable, writable, searchable, and deletable repository abstractions that the tests resolve from the container.

Key APIs

AddEfCoreAggregateDataSource(this IServiceCollection, Action<EfCoreDataSourceOptions>, Action<ServiceOptions>?) registers the non-generic aggregate-aware EF Core data source for applications that only need one implementation. Source shows that it validates the service collection, registers EfCoreAggregateDataSource as both a data source and a unit of work, and stores the supplied EfCoreDataSourceOptions; tests show that the same registration is resolved through IEfCoreDataSource, IDataSource, and IUnitOfWork.

AddEfCoreAggregateDataSource<TMarker>(this IServiceCollection, Action<EfCoreDataSourceOptions<TMarker>>, Action<ServiceOptions>?) is the marker-aware overload for multiple EF Core aggregate sources in one container. The implementation registers EfCoreAggregateDataSource<TMarker> and type-forwards it through IEfCoreDataSource<TMarker>, IDataSource<TMarker>, and IUnitOfWork<TMarker>, which the package tests verify directly.

EfCoreAggregateDataSource<TMarker> is the package-owned wrapper that adapts aggregate-aware EF Core persistence to marker-specific DI resolution. Its constructor accepts IDomainEventDispatcher and EfCoreDataSourceOptions<TMarker>, then builds an EfCoreDbContext<TMarker> and inherits the lower-level EfCoreAggregateDataSource behavior that raises domain events from tracked aggregates before saving changes.

AddEfCoreAggregateRepository<TEntity, TKey>(this IServiceCollection, Action<ServiceOptions>?) registers the default aggregate repository implementation for a single EF Core-backed aggregate store. The source constrains TEntity to IAggregateRoot<IDomainEvent, TKey> and delegates to AddAggregateRepository, while the tests show the resulting service is available through IAggregateRepository<TEntity, TKey> and the lower-level persistent repository contracts.

AddEfCoreAggregateRepository<TEntity, TKey, TMarker>(this IServiceCollection, Action<ServiceOptions>?) adds the same repository pattern with marker-specific resolution. Tests show that one registration is type-forwarded to IAggregateRepository<TEntity, TKey, TMarker>, IPersistentRepository<TEntity, TKey, TMarker>, ISearchableRepository<TEntity, TKey, TMarker>, IDeletableRepository<TEntity, TKey, TMarker>, IReadableRepository<TEntity, TKey, TMarker>, and IWritableRepository<TEntity, TKey, TMarker>.

EfCoreAggregateRepository<TEntity, TKey, TMarker> is the concrete marker-aware repository type exposed by the package. It inherits the EF Core CRUD implementation from EfCoreRepository<TEntity, TKey>, implements IAggregateRepository<TEntity, TKey, TMarker>, and requires an IEfCoreDataSource<TMarker> so aggregate persistence stays tied to the matching marker-qualified data source.

Basic usage

using System;
using System.Threading.Tasks;
using Codebelt.Extensions.Xunit;
using Cuemon.Threading;
using Microsoft.Extensions.DependencyInjection;
using Savvyio.Domain;
using Savvyio.Extensions.DependencyInjection.Domain;
using Savvyio.Extensions.DependencyInjection.EFCore;
using Savvyio.Extensions.DependencyInjection.EFCore.Domain;
using Xunit;

namespace MyProject.Tests;

public class AggregateDataSourceRegistrationTest : Test
{
    public AggregateDataSourceRegistrationTest(ITestOutputHelper output) : base(output) { }

    [Fact]
    public void AddEfCoreAggregateDataSource_WithMarker_RegistersAggregateAwareContracts()
    {
        var services = new ServiceCollection();
        services.AddSingleton<IDomainEventDispatcher, SilentDomainEventDispatcher>();
        services.AddEfCoreAggregateDataSource<OrdersStore>(o => o.ContextConfigurator = _ => { });

        using var provider = services.BuildServiceProvider();
        var source = provider.GetRequiredService<IEfCoreDataSource<OrdersStore>>();
        var unitOfWork = provider.GetRequiredService<IUnitOfWork<OrdersStore>>();

        TestOutput.WriteLine($"Resolved {source.GetType().Name} for aggregate-aware EF Core access.");
        Assert.IsType<EfCoreAggregateDataSource<OrdersStore>>(source);
        Assert.IsType<EfCoreAggregateDataSource<OrdersStore>>(unitOfWork);
    }

    private sealed class OrdersStore;

    private sealed class SilentDomainEventDispatcher : IDomainEventDispatcher
    {
        public void Raise(IDomainEvent request) { }

        public Task RaiseAsync(IDomainEvent request, Action<AsyncOptions>? setup = null)
        {
            return Task.CompletedTask;
        }
    }
}

Use this pattern when one application needs an EF Core aggregate data source registered under an explicit marker so downstream services can resolve the matching implementation.

It matters because the package keeps aggregate-aware EF Core persistence and domain event dispatch behind the same marker-qualified data source and unit-of-work contracts.

Installation

dotnet add package Savvyio.Extensions.DependencyInjection.EFCore.Domain

Usage guidance

Choose this package when your persistence model is built around Savvy I/O aggregate roots and you want EF Core-backed aggregate data sources or repositories wired into Microsoft Dependency Injection, especially when marker types separate multiple stores. If you only need the aggregate-aware EF Core behavior without DI registration, use Savvyio.Extensions.EFCore.Domain; if your EF Core types are not aggregate roots, the more general Savvyio.Extensions.DependencyInjection.EFCore package is the better fit.

Family packages