Skip to content

Lightweight building blocks for implementing Domain-Driven Design (DDD) in .NET applications. Includes base types for Entity, Value Object, Aggregate Root, and Domain Events.

License

Notifications You must be signed in to change notification settings

suranig/AggregateKit

Repository files navigation

AggregateKit

NuGet NuGet Downloads Build codecov License: MIT GitHub

AggregateKit is a lightweight library providing essential building blocks for Domain-Driven Design (DDD) in .NET applications.

Installation

dotnet add package AggregateKit

Features

  • Entity: Base class for domain entities with identity-based equality
  • AggregateRoot: Base class for aggregate roots with domain event handling
  • ValueObject: Base class for value objects with value-based equality
  • DomainEvents: Support for domain events through IDomainEvent and DomainEventBase
  • Result: Functional-style error handling with Result pattern
  • Guard: Utility methods for validating method arguments and enforcing invariants

Quick Start

Value Objects

public class Money : ValueObject
{
    public decimal Amount { get; }
    public string Currency { get; }
    
    public Money(decimal amount, string currency)
    {
        Amount = amount;
        Currency = currency;
    }
    
    protected override IEnumerable<object?> GetEqualityComponents()
    {
        yield return Amount;
        yield return Currency;
    }
}

// Value objects with the same values are equal
var money1 = new Money(100, "USD");
var money2 = new Money(100, "USD");
Console.WriteLine(money1 == money2); // True

Entities

public class Product : Entity<Guid>
{
    public string Name { get; private set; }
    public Money Price { get; private set; }
    
    public Product(Guid id, string name, Money price) : base(id)
    {
        Name = name;
        Price = price;
    }
    
    // Entity behavior methods go here
}

// Entities with the same ID are equal, even if other properties differ
var id = Guid.NewGuid();
var product1 = new Product(id, "Product 1", new Money(100, "USD"));
var product2 = new Product(id, "Updated Name", new Money(110, "USD"));
Console.WriteLine(product1 == product2); // True

Aggregate Roots

public class ArticleCreatedEvent : DomainEventBase
{
    public Guid ArticleId { get; }
    public string Title { get; }
    public string AuthorName { get; }

    public ArticleCreatedEvent(Guid articleId, string title, string authorName)
    {
        ArticleId = articleId;
        Title = title;
        AuthorName = authorName;
    }
}

public class Article : AggregateRoot<Guid>
{
    public string Title { get; private set; }
    public string Content { get; private set; }
    public string AuthorName { get; private set; }
    public bool IsPublished { get; private set; }
    public DateTime? PublishDate { get; private set; }

    private Article() { }

    public Article(Guid id, string title, string content, string authorName) : base(id)
    {
        Title = title;
        Content = content;
        AuthorName = authorName;
        IsPublished = false;
        PublishDate = null;
        
        AddDomainEvent(new ArticleCreatedEvent(id, title, authorName));
    }

    public void Publish()
    {
        if (IsPublished)
            return;
        
        IsPublished = true;
        PublishDate = DateTime.UtcNow;
        
        AddDomainEvent(new ArticlePublishedEvent(Id, PublishDate.Value));
    }
}

Result Pattern

public Result<Article> CreateArticle(string title, string content, string authorName)
{
    if (string.IsNullOrWhiteSpace(title))
        return Result<Article>.Failure("Title cannot be empty");
        
    if (string.IsNullOrWhiteSpace(authorName))
        return Result<Article>.Failure("Author name cannot be empty");
        
    var article = new Article(Guid.NewGuid(), title, content, authorName);
    return Result<Article>.Success(article);
}

// Usage
var result = CreateArticle("Domain-Driven Design", "DDD concepts explained...", "Eric Evans");
if (result.IsSuccess)
{
    var article = result.Value;
    // Process the article
}
else
{
    // Handle errors
    foreach (var error in result.Errors)
    {
        Console.WriteLine(error);
    }
}

Development

This project includes Docker support and a Makefile for development workflows:

# Run tests
make test

# Run tests in Docker
make docker-test

# Build the package
make pack

See DEVELOPMENT.md for complete development instructions.

License

This project is licensed under the MIT License - see the LICENSE file for details.

About

Lightweight building blocks for implementing Domain-Driven Design (DDD) in .NET applications. Includes base types for Entity, Value Object, Aggregate Root, and Domain Events.

Resources

License

Stars

Watchers

Forks

Packages

No packages published