Introduction
The Hybrid DDD Architecture includes several reusable core modules that provide common infrastructure functionality. These modules can be shared across multiple projects and provide consistent patterns for CQRS, event handling, persistence, and more.
Module Overview
The core modules are organized by responsibility:
Command/Query Bus CQRS implementation using MediatR
Event Bus Event publishing and subscription abstractions
Repositories Generic repository interfaces for data access
Mapping Object-to-object mapping utilities
HTTP Adapters HTTP client abstractions for external APIs
Domain Base entity classes and validation
Core.Application.CommandQueryBus
Provides abstractions and implementations for the CQRS pattern using MediatR.
Key Components
ICommandQueryBus
The main bus interface for sending commands, queries, and publishing notifications.
public interface ICommandQueryBus
{
Task Publish < TNotification >( TNotification notification , CancellationToken cancellationToken = default )
where TNotification : INotification ;
Task Send ( IRequest request , CancellationToken cancellationToken = default );
Task < TResponse > Send < TResponse >( IRequest < TResponse > request , CancellationToken cancellationToken = default );
}
Command Interfaces
Define command contracts for write operations.
public interface IRequestCommand : IRequest
{
}
public interface IRequestCommand < out TResponse > : IRequest < TResponse >
{
}
Query Interfaces
Define query contracts for read operations.
public interface IRequestQuery : IRequest
{
}
public interface IRequestQuery < out TResponse > : IRequest < TResponse >
{
}
Handler Interfaces
Define handler contracts for processing commands and queries.
public interface IRequestCommandHandler < in TRequest > : IRequestHandler < TRequest >
where TRequest : IRequest
{
}
public interface IRequestCommandHandler < TRequest , TResponse > : IRequestHandler < TRequest , TResponse >
where TRequest : IRequest < TResponse >
{
}
Source : Core.Application.CommandQueryBus/Commands/IRequestCommandHandler.cs:5-13
Notifications and Domain Events
Support for domain event notifications.
public class DomainEvent : IRequestNotification
{
public DateTime EventDateUtc { get ; private set ; }
public DomainEvent ()
{
EventDateUtc = DateTime . UtcNow ;
}
}
Source : Core.Application.CommandQueryBus/Notifications/DomainEvent.cs:3-10
QueryRequest and QueryResult
Base classes for paginated queries.
public class QueryRequest < TResponse > : IRequestQuery < TResponse >
where TResponse : class
{
public uint PageIndex { get ; set ; }
public uint PageSize { get ; set ; }
}
Source : Core.Application.CommandQueryBus/Queries/QueryRequest.cs:3-8
public class QueryResult < TEntity >
where TEntity : class
{
public long Count { get ; private set ; }
public IEnumerable < TEntity > Items { get ; private set ; }
public uint PageIndex { get ; private set ; }
public uint PageSize { get ; private set ; }
public QueryResult ( IEnumerable < TEntity > items , long count , uint pageSize , uint pageIndex )
{
Items = items ;
Count = count ;
PageIndex = pageIndex ;
PageSize = pageSize ;
}
}
Source : Core.Application.CommandQueryBus/Queries/QueryResult.cs:3-17
The QueryResult class provides built-in pagination support for query responses.
Core.Application.EventBus
Provides abstractions for event-driven architecture with support for integration events.
Key Components
IEventBus
The main event bus interface for publishing and subscribing to integration events.
public interface IEventBus
{
void Publish ( IntegrationEvent @event );
void Subscribe < TEvent , THandler >()
where TEvent : IntegrationEvent
where THandler : IIntegrationEventHandler < TEvent >;
void SubscribeDynamic < THandler >( string eventName )
where THandler : IDynamicIntegrationEventHandler ;
void Unsubscribe < TEvent , THandler >()
where TEvent : IntegrationEvent
where THandler : IIntegrationEventHandler < TEvent >;
void UnsubscribeDynamic < THandler >( string eventName )
where THandler : IDynamicIntegrationEventHandler ;
}
Source : Core.Application.EventBus/Buses/IEventBus.cs:3-20
IntegrationEvent
Base class for all integration events.
public abstract class IntegrationEvent
{
[ JsonProperty ]
public Guid Id { get ; private set ; }
[ JsonProperty ]
public DateTime CreateDateUtc { get ; private set ; }
[ JsonProperty ]
public string EventType { get ; private set ; }
[ JsonProperty ]
public string Subject { get ; private set ; }
[ JsonProperty ]
public object Data { get ; private set ; }
protected IntegrationEvent ( string eventType , string subject , object data )
{
Id = Guid . NewGuid ();
CreateDateUtc = DateTime . UtcNow . ToLocalTime ();
EventType = eventType ;
Subject = subject ;
Data = data ;
}
}
Source : Core.Application.EventBus/Events/IntegrationEvent.cs:5-35
Infrastructure Implementation
The template includes a RabbitMQ implementation:
Core.Infrastructure.EventBus.RabbitMq : RabbitMQ-based event bus implementation
Supports publish/subscribe patterns
Includes retry policies and connection management
Handles dynamic and typed event subscriptions
Source : Core.Infrastructure.EventBus.RabbitMq/Buses/RabbitMqEventBus.cs
The event bus requires proper configuration of RabbitMQ connection settings in your application.
Core.Application.Repositories
Provides generic repository abstractions for data access.
IRepository Interface
public interface IRepository < TEntity >
{
object Add ( TEntity entity );
Task < object > AddAsync ( TEntity entity );
long Count ( Expression < Func < TEntity , bool >> filter );
Task < long > CountAsync ( Expression < Func < TEntity , bool >> filter );
List < TEntity > FindAll ();
Task < List < TEntity >> FindAllAsync ();
TEntity FindOne ( params object [] keyValues );
Task < TEntity > FindOneAsync ( params object [] keyValues );
void Remove ( params object [] keyValues );
void Update ( object id , TEntity entity );
}
Source : Core.Application.Repositories/IRepository.cs:5-17
Infrastructure Implementations
The template includes two repository implementations:
MongoDB Repository
public class BaseRepository < TEntity > : IRepository < TEntity > where TEntity : class
{
public DbContext Context { get ; private set ; }
public IMongoCollection < TEntity > Collection { get ; private set ; }
public BaseRepository ( DbContext context )
{
Context = context ;
Collection = Context . GetCollection < TEntity >();
}
public async Task < object > AddAsync ( TEntity entity )
{
await Collection . InsertOneAsync ( entity );
var property = typeof ( TEntity ). GetProperty ( "Id" ) ?? typeof ( TEntity ). GetProperty ( "_id" );
return ( object ) property ? . GetValue ( entity );
}
// ... other methods
}
Source : Core.Infrastructure.Repositories.MongoDb/BaseRepository.cs:7-31
SQL Server Repository
Core.Infrastructure.Repositories.Sql : Entity Framework Core-based implementation
Supports SQL Server with migrations
Includes DbContext configuration
You can easily switch between MongoDB and SQL Server by changing your dependency injection configuration.
Core.Application.Mapping
Provides utilities for object-to-object mapping using AutoMapper.
CustomMapper
Extension methods for convenient mapping.
public static class CustomMapper
{
public static IMapper Instance { get ; set ; }
public static T To < T >( this object input )
{
IMapper mapper = Instance ;
return mapper . Map < T >( input );
}
public static T To < T >( this IValidate input )
{
IMapper mapper = Instance ;
return mapper . Map < T >( input );
}
public static IEnumerable < T > To < T >( this IEnumerable < IValidate > input )
{
IMapper mapper = Instance ;
return mapper . Map < IEnumerable < T >>( input );
}
}
Source : Core.Application.Mapping/CustomMapper.cs:6-28
Usage Example
// Map entity to DTO
DummyEntityDto dto = entity . To < DummyEntityDto >();
// Map collection
IEnumerable < DummyEntityDto > dtos = entities . To < DummyEntityDto >();
Core.Application.Adapters.Http
Provides abstractions for HTTP client operations.
IExternalApiClient
public interface IExternalApiClient
{
Task < string > GetAsync ( string url , Tuple < string , string >? authentication = null ,
IDictionary < string , string >? headers = null );
Task < HttpResponseMessage > PostAsync < T >( string uri , T item ,
Tuple < string , string >? authentication = null , IDictionary < string , string >? headers = null );
Task < HttpResponseMessage > PutAsync < T >( string url , T item ,
Tuple < string , string >? authentication = null , IDictionary < string , string >? headers = null );
Task < HttpResponseMessage > DeleteAsync ( string url ,
Tuple < string , string >? authentication = null , IDictionary < string , string >? headers = null );
}
Source : Core.Application.Adapters.Http/IExternalApiClient.cs:3-9
Features
Supports authentication headers
Custom header injection
RESTful operations (GET, POST, PUT, DELETE)
Async/await pattern
The HTTP adapter provides a consistent interface for all external API calls, making it easy to mock in tests.
Core.Domain
Provides base classes for domain entities with built-in validation.
DomainEntity
Base class for all domain entities.
public class DomainEntity < TKey , TValidator > : IValidate
where TValidator : IValidator , new ()
{
public TKey Id { get ; protected set ; }
public bool IsValid
{
get
{
Validate ();
return ValidationResult . IsValid ;
}
}
protected TValidator Validator { get ; }
private ValidationResult ValidationResult { get ; set ; }
protected DomainEntity ()
{
Validator = new TValidator ();
}
protected void Validate ()
{
var context = new ValidationContext < object >( this );
ValidationResult = Validator . Validate ( context );
}
public IList < ValidationFailure > GetErrors ()
{
Validate ();
return ValidationResult . Errors ;
}
}
Source : Core.Domain/Entities/DomainEntity.cs:13-44
Features
Generic key type support
Integrated FluentValidation
Self-validating entities
Immutable validation results
Usage Example
public class DummyEntity : DomainEntity < string , DummyEntityValidator >
{
public string DummyPropertyOne { get ; private set ; }
public DummyValues DummyPropertyTwo { get ; private set ; }
public DummyEntity ( string dummyPropertyOne , DummyValues dummyPropertyTwo )
{
Id = Guid . NewGuid (). ToString ();
SetdummyPropertyOne ( dummyPropertyOne );
DummyPropertyTwo = dummyPropertyTwo ;
}
public void SetdummyPropertyOne ( string value )
{
DummyPropertyOne = value ?? throw new ArgumentNullException ( nameof ( value ));
}
}
Source : Domain/Entities/DummyEntity.cs:12-42
Domain entity properties should have private setters to enforce invariants through methods.
Module Dependencies
The core modules have the following dependency structure:
Core.Domain (no dependencies)
↑
Core.Application.* (depends on Core.Domain)
↑
Core.Infrastructure.* (depends on Core.Application.*)
This structure ensures that:
Domain logic remains pure and independent
Application abstractions are framework-agnostic
Infrastructure provides concrete implementations
Next Steps
Architecture Layers Learn how layers use these core modules
CQRS Pattern See CQRS implementation in action
Domain Layer Create your first domain entity
Repositories Implement data persistence