Clean Architecture Domain Layer - Core Domain Models, Entities, Value Objects, and Domain Events
$ dotnet add package AkbarAmd.SharedKernel.DomainClean Architecture Domain Layer - Core Domain Models, Entities, Value Objects, and Domain Events
The Domain layer is the core of Clean Architecture, containing business logic, domain models, and domain rules. This package provides foundational building blocks for implementing Domain-Driven Design (DDD) patterns in .NET applications.
This layer defines:
Entity<TKey>: Base entity class with identity managementAggregateRoot<TKey>: Aggregate root with domain events and concurrency controlCreatableAggregateRoot<TKey>: Aggregate root with creation trackingModifiableAggregateRoot<TKey>: Aggregate root with modification trackingSoftDeletableAggregateRoot<TKey>: Aggregate root with soft delete supportFullAggregateRoot<TKey>: Complete aggregate root with all tracking featuresValueObject: Immutable value object base classEnumeration: Smart enumeration pattern for domain constantsIDomainEvent: Interface for domain eventsIBusinessRule: Interface for domain business rules and invariantsBaseBusinessRule: Base class for implementing business rulesDomainBusinessRuleValidationException: Exception thrown when business rules are violatedISpecification<T>: Specification pattern interfaceBaseSpecification<T>: Base class for building specificationsFluentSpecificationBuilder<T>: Fluent API for building query criteriaCriteriaChain<T>: Chain multiple criteria togetherOutboxMessage: Aggregate root for reliable message processingIRepository<T, TKey>: Generic repository interfaceIReadOnlyRepository<T, TKey>: Read-only repository interfacedotnet add package AkbarAmd.SharedKernel.Domain
using AkbarAmd.SharedKernel.Domain.AggregateRoots;
using AkbarAmd.SharedKernel.Domain.BusinessRules;
public class User : AggregateRoot<Guid>
{
public string Email { get; private set; }
public string Name { get; private set; }
private User() { } // For EF Core
public User(string email, string name)
{
Id = Guid.NewGuid();
// Business rule validation - CheckRule is inherited from Entity base class
CheckRule(new EmailCannotBeEmptyRule(email));
CheckRule(new NameCannotBeEmptyRule(name));
Email = email;
Name = name;
// Raise domain event
AddDomainEvent(new UserCreatedEvent(Id, Email));
}
public void UpdateName(string newName)
{
// Business rule validation
CheckRule(new NameCannotBeEmptyRule(newName));
Name = newName;
AddDomainEvent(new UserNameChangedEvent(Id, newName));
}
public void Deactivate()
{
CheckRule(new UserCanBeDeactivatedRule(IsActive));
IsActive = false;
AddDomainEvent(new UserDeactivatedEvent(Id));
}
}
// Business Rule Implementation
using AkbarAmd.SharedKernel.Domain.BusinessRules;
public class NameCannotBeEmptyRule : BaseBusinessRule
{
private readonly string _name;
public NameCannotBeEmptyRule(string name)
{
_name = name;
}
public override bool IsSatisfied() => !string.IsNullOrWhiteSpace(_name);
public override string Message => "Name cannot be empty";
}
public class Email : ValueObject
{
public string Value { get; }
public Email(string value)
{
if (string.IsNullOrWhiteSpace(value) || !value.Contains("@"))
throw new ArgumentException("Invalid email");
Value = value;
}
protected override IEnumerable<object> GetEqualityComponents()
{
yield return Value;
}
}
var activeUsersSpec = new CriteriaBuilder<User>()
.Where(u => u.IsActive)
.OrderBy(u => u.CreatedAt)
.Take(10)
.Build();
var users = await repository.GetAsync(activeUsersSpec);
This layer follows Clean Architecture principles:
MIT License - see LICENSE file for details.
Akbar Ahmadi Saray - GitHub