Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [1.11.0] - 2026-02-06

### Added

- Added two overloads for Dependency injection offering the use of a custom configuration type for Table and View repositories respectively.
- This can be useful if you want to add extra configuration to your repos and don't want to deal with the overload taking a constructor delegate.
1 change: 1 addition & 0 deletions Dapper.DDD.Repository.sln
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
.editorconfig = .editorconfig
Directory.Build.props = Directory.Build.props
Directory.Packages.props = Directory.Packages.props
CHANGELOG.md = CHANGELOG.md
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapper.DDD.Repository.PostGreSql", "src\Dapper.DDD.Repository.PostGreSql\Dapper.DDD.Repository.PostGreSql.csproj", "{92DAD05A-C310-40D0-BB38-D27C4B565EC3}"
Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<!-- Directory.Build.props -->
<Project>
<PropertyGroup>
<Version>1.10.3</Version>
<Version>1.11.0</Version>
</PropertyGroup>
</Project>

Original file line number Diff line number Diff line change
@@ -1,21 +1,6 @@
using Dapper.DDD.Repository.Configuration;
using Dapper.DDD.Repository.Interfaces;
using Dapper.DDD.Repository.Repositories;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;

namespace Dapper.DDD.Repository.DependencyInjection;

public delegate TRepository TableRepositoryConstructorDelegate<TAggregate, out TRepository>(
IOptions<TableAggregateConfiguration<TAggregate>> options, IOptions<DefaultConfiguration>? defaultOptions, IServiceProvider provider)
where TAggregate : notnull;

public delegate TRepository ViewRepositoryConstructorDelegate<TAggregate, out TRepository>(
IOptions<ViewAggregateConfiguration<TAggregate>> options, IOptions<DefaultConfiguration>? defaultOptions,
IServiceProvider provider)
where TAggregate : notnull;

public static class DapperRepositoryDependencyInjection
public static partial class DapperRepositoryDependencyInjection
{
/// <summary>
/// Configure defaults to use for all aggregate types.
Expand All @@ -25,195 +10,4 @@ public static IServiceCollection ConfigureDapperRepositoryDefaults(this IService
{
return services.Configure(configureOptions);
}

/// <summary>
/// Add a table repository for the given aggregate type to the dependency injection system.
/// You can request an ITableRepository<TAggregate, TAggregateId> through the dependency injection system afterwards.
/// </summary>
public static IServiceCollection AddTableRepository<TAggregate, TAggregateId>(this IServiceCollection services,
Action<TableAggregateConfiguration<TAggregate>> configureOptions)
where TAggregate : notnull
where TAggregateId : notnull
{
services.Configure(configureOptions);
services
.AddSingleton<ITableRepository<TAggregate, TAggregateId>, TableRepository<TAggregate, TAggregateId>>();
return services;
}

/// <summary>
/// Add a view repository for the given aggregate type to the dependency injection system.
/// You can request an IViewRepository<TAggregate, TAggregateId> through the dependency injection system afterwards.
/// </summary>
public static IServiceCollection AddViewRepository<TAggregate, TAggregateId>(this IServiceCollection services,
Action<ViewAggregateConfiguration<TAggregate>> configureOptions)
where TAggregate : notnull
where TAggregateId : notnull
{
services.Configure(configureOptions);
services
.AddSingleton<IViewRepository<TAggregate, TAggregateId>, ViewRepository<TAggregate, TAggregateId>>();
return services;
}

/// <summary>
/// Add a view repository for the given aggregate type to the dependency injection system.
/// You can request an IViewRepository<TAggregate> through the dependency injection system afterwards.
/// </summary>
public static IServiceCollection AddViewRepository<TAggregate>(this IServiceCollection services,
Action<ViewAggregateConfiguration<TAggregate>> configureOptions)
where TAggregate : notnull
{
services.Configure(configureOptions);
services.AddSingleton<IViewRepository<TAggregate>, ViewRepository<TAggregate>>();
return services;
}

/// <summary>
/// Add a table repository for the given aggregate type to the dependency injection system.
/// Uses a custom class and interface, allowing you to inherit from the built-in TableRepository type.
/// </summary>
/// <typeparam name="TAggregate">Type of your aggregate</typeparam>
/// <typeparam name="TAggregateId">Type of your aggregate's Id</typeparam>
/// <typeparam name="TRepositoryInterface">Interface type of your repository</typeparam>
/// <typeparam name="TRepositoryClass">Actual implementation type of your repository</typeparam>
/// <param name="configureOptions">Used to configure the repository via lambda</param>
public static IServiceCollection AddTableRepository<TAggregate, TAggregateId, TRepositoryInterface,
TRepositoryClass>(this IServiceCollection services,
Action<TableAggregateConfiguration<TAggregate>> configureOptions)
where TAggregate : notnull
where TAggregateId : notnull
where TRepositoryInterface : class
where TRepositoryClass : TableRepository<TAggregate, TAggregateId>, TRepositoryInterface
{
services.Configure(configureOptions);
services.AddSingleton<TRepositoryInterface, TRepositoryClass>();
return services;
}


/// <summary>
/// Add a table repository for the given aggregate type to the dependency injection system.
/// Uses a custom class and interface, allowing you to inherit from the built-in TableRepository type.
/// Takes a custom function to create the actual instance, allowing you to set any instance-specific state.
/// </summary>
/// <typeparam name="TAggregate">Type of your aggregate</typeparam>
/// <typeparam name="TAggregateId">Type of your aggregate's Id</typeparam>
/// <typeparam name="TRepositoryInterface">Interface type of your repository</typeparam>
/// <typeparam name="TRepositoryClass">Actual implementation type of your repository</typeparam>
/// <param name="configureOptions">Used to configure the repository via lambda</param>
public static IServiceCollection AddTableRepository<TAggregate, TAggregateId, TRepositoryInterface,
TRepositoryClass>(this IServiceCollection services,
Action<TableAggregateConfiguration<TAggregate>> configureOptions,
TableRepositoryConstructorDelegate<TAggregate, TRepositoryClass> constructor)
where TAggregate : notnull
where TAggregateId : notnull
where TRepositoryInterface : class
where TRepositoryClass : TableRepository<TAggregate, TAggregateId>, TRepositoryInterface
{
services.Configure(configureOptions);
services.AddSingleton<TRepositoryInterface>(provider =>
{
var configuration = provider.GetRequiredService<IOptions<TableAggregateConfiguration<TAggregate>>>();
var defaultConfiguration = provider.GetService<IOptions<DefaultConfiguration>>();
return constructor(configuration, defaultConfiguration, provider);
});
return services;
}

/// <summary>
/// Add a view repository for the given aggregate type to the dependency injection system.
/// Uses a custom class and interface, allowing you to inherit from the built-in ViewRepository type.
/// </summary>
/// <typeparam name="TAggregate">Type of your aggregate</typeparam>
/// <typeparam name="TAggregateId">Type of your aggregate's Id</typeparam>
/// <typeparam name="TRepositoryInterface">Interface type of your repository</typeparam>
/// <typeparam name="TRepositoryClass">Actual implementation type of your repository</typeparam>
/// <param name="configureOptions">Used to configure the repository via lambda</param>
public static IServiceCollection AddViewRepository<TAggregate, TAggregateId, TRepositoryInterface,
TRepositoryClass>(this IServiceCollection services,
Action<ViewAggregateConfiguration<TAggregate>> configureOptions)
where TAggregate : notnull
where TAggregateId : notnull
where TRepositoryInterface : class
where TRepositoryClass : ViewRepository<TAggregate, TAggregateId>, TRepositoryInterface
{
services.Configure(configureOptions);
services.AddSingleton<TRepositoryInterface, TRepositoryClass>();
return services;
}

/// <summary>
/// Add a view repository for the given aggregate type to the dependency injection system.
/// Uses a custom class and interface, allowing you to inherit from the built-in ViewRepository type.
/// Takes a custom function to create the actual instance, allowing you to set any instance-specific state.
/// </summary>
/// <typeparam name="TAggregate">Type of your aggregate</typeparam>
/// <typeparam name="TAggregateId">Type of your aggregate's Id</typeparam>
/// <typeparam name="TRepositoryInterface">Interface type of your repository</typeparam>
/// <typeparam name="TRepositoryClass">Actual implementation type of your repository</typeparam>
/// <param name="configureOptions">Used to configure the repository via lambda</param>
public static IServiceCollection AddViewRepository<TAggregate, TAggregateId, TRepositoryInterface,
TRepositoryClass>(this IServiceCollection services,
Action<ViewAggregateConfiguration<TAggregate>> configureOptions,
ViewRepositoryConstructorDelegate<TAggregate, TRepositoryClass> constructor)
where TAggregate : notnull
where TAggregateId : notnull
where TRepositoryInterface : class
where TRepositoryClass : ViewRepository<TAggregate, TAggregateId>, TRepositoryInterface
{
services.Configure(configureOptions);
services.AddSingleton<TRepositoryInterface>(provider =>
{
var configuration = provider.GetRequiredService<IOptions<ViewAggregateConfiguration<TAggregate>>>();
var defaultConfiguration = provider.GetService<IOptions<DefaultConfiguration>>();
return constructor(configuration, defaultConfiguration, provider);
});
return services;
}

/// <summary>
/// Add a view repository for the given aggregate type to the dependency injection system.
/// Uses a custom class and interface, allowing you to inherit from the built-in ViewRepository type.
/// </summary>
/// <typeparam name="TAggregate">Type of your aggregate</typeparam>
/// <typeparam name="TRepositoryInterface">Interface type of your repository</typeparam>
/// <typeparam name="TRepositoryClass">Actual implementation type of your repository</typeparam>
/// <param name="configureOptions">Used to configure the repository via lambda</param>
public static IServiceCollection AddViewRepository<TAggregate, TRepositoryInterface, TRepositoryClass>(
this IServiceCollection services, Action<ViewAggregateConfiguration<TAggregate>> configureOptions)
where TAggregate : notnull
where TRepositoryInterface : class
where TRepositoryClass : ViewRepository<TAggregate>, TRepositoryInterface
{
services.Configure(configureOptions);
services.AddSingleton<TRepositoryInterface, TRepositoryClass>();
return services;
}

/// <summary>
/// Add a view repository for the given aggregate type to the dependency injection system.
/// Uses a custom class and interface, allowing you to inherit from the built-in ViewRepository type.
/// Takes a custom function to create the actual instance, allowing you to set any instance-specific state.
/// </summary>
/// <typeparam name="TAggregate">Type of your aggregate</typeparam>
/// <typeparam name="TRepositoryInterface">Interface type of your repository</typeparam>
/// <typeparam name="TRepositoryClass">Actual implementation type of your repository</typeparam>
/// <param name="configureOptions">Used to configure the repository via lambda</param>
public static IServiceCollection AddViewRepository<TAggregate, TRepositoryInterface, TRepositoryClass>(
this IServiceCollection services, Action<ViewAggregateConfiguration<TAggregate>> configureOptions,
ViewRepositoryConstructorDelegate<TAggregate, TRepositoryClass> constructor)
where TAggregate : notnull
where TRepositoryInterface : class
where TRepositoryClass : ViewRepository<TAggregate>, TRepositoryInterface
{
services.Configure(configureOptions);
services.AddSingleton<TRepositoryInterface>(provider =>
{
var configuration = provider.GetRequiredService<IOptions<ViewAggregateConfiguration<TAggregate>>>();
var defaultConfiguration = provider.GetService<IOptions<DefaultConfiguration>>();
return constructor(configuration, defaultConfiguration, provider);
});
return services;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
namespace Dapper.DDD.Repository.DependencyInjection;

public delegate TRepository TableRepositoryConstructorDelegate<TAggregate, out TRepository>(
IOptions<TableAggregateConfiguration<TAggregate>> options, IOptions<DefaultConfiguration>? defaultOptions, IServiceProvider provider)
where TAggregate : notnull;

public static partial class DapperRepositoryDependencyInjection
{
/// <summary>
/// Add a table repository for the given aggregate type to the dependency injection system.
/// You can request an ITableRepository<TAggregate, TAggregateId> through the dependency injection system afterwards.
/// </summary>
public static IServiceCollection AddTableRepository<TAggregate, TAggregateId>(this IServiceCollection services,
Action<TableAggregateConfiguration<TAggregate>> configureOptions)
where TAggregate : notnull
where TAggregateId : notnull
{
services.Configure(configureOptions);
services
.AddSingleton<ITableRepository<TAggregate, TAggregateId>, TableRepository<TAggregate, TAggregateId>>();
return services;
}

/// <summary>
/// Add a table repository for the given aggregate type to the dependency injection system.
/// Uses a custom class and interface, allowing you to inherit from the built-in TableRepository type.
/// </summary>
/// <typeparam name="TAggregate">Type of your aggregate</typeparam>
/// <typeparam name="TAggregateId">Type of your aggregate's Id</typeparam>
/// <typeparam name="TRepositoryInterface">Interface type of your repository</typeparam>
/// <typeparam name="TRepositoryClass">Actual implementation type of your repository</typeparam>
/// <param name="configureOptions">Used to configure the repository via lambda</param>
public static IServiceCollection AddTableRepository<TAggregate, TAggregateId, TRepositoryInterface,
TRepositoryClass>(this IServiceCollection services,
Action<TableAggregateConfiguration<TAggregate>> configureOptions)
where TAggregate : notnull
where TAggregateId : notnull
where TRepositoryInterface : class
where TRepositoryClass : TableRepository<TAggregate, TAggregateId>, TRepositoryInterface
{
services.Configure(configureOptions);
services.AddSingleton<TRepositoryInterface, TRepositoryClass>();
return services;
}

/// <summary>
/// Add a table repository for the given aggregate type to the dependency injection system.
/// Uses a custom class and interface, allowing you to inherit from the built-in TableRepository type.
/// </summary>
/// <typeparam name="TAggregate">Type of your aggregate</typeparam>
/// <typeparam name="TAggregateId">Type of your aggregate's Id</typeparam>
/// <typeparam name="TRepositoryInterface">Interface type of your repository</typeparam>
/// <typeparam name="TRepositoryClass">Actual implementation type of your repository</typeparam>
/// <typeparam name="TConfiguration">
/// Custom type of configuration for your repository, useful if you want to append custom
/// configuration. Your repository constructor should expect this type instead of TableAggregateConfiguration&lt;
/// TAggregate&gt;.
/// </typeparam>
/// <param name="configureOptions">Used to configure the repository via lambda</param>
public static IServiceCollection AddTableRepository<TAggregate, TAggregateId, TRepositoryInterface,
TRepositoryClass, TConfiguration>(this IServiceCollection services,
Action<TConfiguration> configureOptions)
where TAggregate : notnull
where TAggregateId : notnull
where TRepositoryInterface : class
where TRepositoryClass : TableRepository<TAggregate, TAggregateId>, TRepositoryInterface
where TConfiguration : TableAggregateConfiguration<TAggregate>, new()
{
var ctorInfo = typeof(TRepositoryClass).GetConstructor([typeof(IOptions<TConfiguration>), typeof(IOptions<DefaultConfiguration>)]);
if (ctorInfo is null || ctorInfo.GetParameters()[0].ParameterType != typeof(IOptions<TConfiguration>))
{
throw new ArgumentException($"The constructor for {typeof(TRepositoryClass).Name} does not take IOptions<{typeof(TConfiguration).Name}> as argument!", nameof(configureOptions));
}

services.Configure(configureOptions);
services.AddSingleton<TRepositoryInterface, TRepositoryClass>();
return services;
}


/// <summary>
/// Add a table repository for the given aggregate type to the dependency injection system.
/// Uses a custom class and interface, allowing you to inherit from the built-in TableRepository type.
/// Takes a custom function to create the actual instance, allowing you to set any instance-specific state.
/// </summary>
/// <typeparam name="TAggregate">Type of your aggregate</typeparam>
/// <typeparam name="TAggregateId">Type of your aggregate's Id</typeparam>
/// <typeparam name="TRepositoryInterface">Interface type of your repository</typeparam>
/// <typeparam name="TRepositoryClass">Actual implementation type of your repository</typeparam>
/// <param name="configureOptions">Used to configure the repository via lambda</param>
public static IServiceCollection AddTableRepository<TAggregate, TAggregateId, TRepositoryInterface,
TRepositoryClass>(this IServiceCollection services,
Action<TableAggregateConfiguration<TAggregate>> configureOptions,
TableRepositoryConstructorDelegate<TAggregate, TRepositoryClass> constructor)
where TAggregate : notnull
where TAggregateId : notnull
where TRepositoryInterface : class
where TRepositoryClass : TableRepository<TAggregate, TAggregateId>, TRepositoryInterface
{
services.Configure(configureOptions);
services.AddSingleton<TRepositoryInterface>(provider =>
{
var configuration = provider.GetRequiredService<IOptions<TableAggregateConfiguration<TAggregate>>>();
var defaultConfiguration = provider.GetService<IOptions<DefaultConfiguration>>();
return constructor(configuration, defaultConfiguration, provider);
});
return services;
}
}
Loading