Trellis.DomainDrivenDesign 3.0.0-alpha.99

This is a prerelease version of Trellis.DomainDrivenDesign.
dotnet add package Trellis.DomainDrivenDesign --version 3.0.0-alpha.99
                    
NuGet\Install-Package Trellis.DomainDrivenDesign -Version 3.0.0-alpha.99
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Trellis.DomainDrivenDesign" Version="3.0.0-alpha.99" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Trellis.DomainDrivenDesign" Version="3.0.0-alpha.99" />
                    
Directory.Packages.props
<PackageReference Include="Trellis.DomainDrivenDesign" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Trellis.DomainDrivenDesign --version 3.0.0-alpha.99
                    
#r "nuget: Trellis.DomainDrivenDesign, 3.0.0-alpha.99"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Trellis.DomainDrivenDesign@3.0.0-alpha.99
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Trellis.DomainDrivenDesign&version=3.0.0-alpha.99&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Trellis.DomainDrivenDesign&version=3.0.0-alpha.99&prerelease
                    
Install as a Cake Tool

Domain Driven Design

NuGet Package

Building blocks for implementing Domain-Driven Design tactical patterns in C# with functional programming principles.

Installation

dotnet add package Trellis.DomainDrivenDesign

Quick Start

Entity

Objects with unique identity. Equality based on ID.

public partial class CustomerId : RequiredGuid<CustomerId> { }

public class Customer : Entity<CustomerId>
{
    public string Name { get; private set; }
    
    private Customer(CustomerId id, string name) : base(id)
    {
        Name = name;
    }
    
    public static Result<Customer> TryCreate(string name) =>
        name.ToResult()
            .Ensure(n => !string.IsNullOrWhiteSpace(n), Error.Validation("Name required"))
            .Map(n => new Customer(CustomerId.NewUniqueV7(), n));
}

Value Object

Immutable objects with no identity. Equality based on all properties.

public class Money : ValueObject
{
    public decimal Amount { get; }
    public string Currency { get; }
    
    private Money(decimal amount, string currency)
    {
        Amount = amount;
        Currency = currency;
    }
    
    public static Result<Money> TryCreate(decimal amount, string currency = "USD") =>
        (amount, currency).ToResult()
            .Ensure(x => x.amount >= 0, Error.Validation("Amount cannot be negative"))
            .Map(x => new Money(x.amount, x.currency));
    
    protected override IEnumerable<IComparable> GetEqualityComponents()
    {
        yield return Amount;
        yield return Currency;
    }
}

Aggregate

Cluster of entities and value objects treated as a unit. Manages domain events.

public record OrderCreated(OrderId Id, CustomerId CustomerId, DateTime OccurredAt) : IDomainEvent;

public class Order : Aggregate<OrderId>
{
    private readonly List<OrderLine> _lines = [];
    
    public CustomerId CustomerId { get; }
    public OrderStatus Status { get; private set; }
    
    private Order(OrderId id, CustomerId customerId) : base(id)
    {
        CustomerId = customerId;
        Status = OrderStatus.Draft;
        DomainEvents.Add(new OrderCreated(id, customerId, DateTime.UtcNow));
    }
    
    public static Result<Order> TryCreate(CustomerId customerId) =>
        new Order(OrderId.NewUniqueV7(), customerId).ToResult();
    
    public Result<Order> AddLine(ProductId productId, string name, Money price, int qty) =>
        this.ToResult()
            .Ensure(_ => Status == OrderStatus.Draft, Error.Validation("Order not editable"))
            .Ensure(_ => qty > 0, Error.Validation("Quantity must be positive"))
            .Tap(_ => _lines.Add(new OrderLine(productId, name, price, qty)));
}

Specification

Encapsulate business rules as composable, storage-agnostic expression trees.

public class HighValueOrderSpec(decimal threshold) : Specification<Order>
{
    public override Expression<Func<Order, bool>> ToExpression() =>
        order => order.TotalAmount > threshold;
}

// Compose specifications
var spec = new OverdueOrderSpec(now).And(new HighValueOrderSpec(500m));

// Use with EF Core
var orders = await dbContext.Orders.Where(spec).ToListAsync();

// In-memory evaluation
if (spec.IsSatisfiedBy(order))
    // order matches

Domain Events

Publish events after persisting:

if (order.IsSuccess)
{
    await repository.SaveAsync(order.Value);
    
    foreach (var evt in order.Value.UncommittedEvents())
        await eventBus.PublishAsync(evt);
    
    order.Value.AcceptChanges();
}

Core Types

Type Purpose Equality
Entity<TId> Objects with identity By ID
ValueObject Immutable, no identity By all properties
ScalarValueObject<TSelf, T> Wraps single primitive By value
Aggregate<TId> Consistency boundary + events By ID
Specification<T> Composable business rules
IDomainEvent Marker for domain events

Best Practices

  1. Use entities when identity mattersCustomer : Entity<CustomerId>
  2. Keep aggregates small — Include only what's needed for invariants
  3. Reference other aggregates by IDpublic CustomerId CustomerId { get; } not public Customer Customer { get; }
  4. Use Maybe<T> for optional propertiesMaybe<Url> Website instead of Url?
  5. Enforce invariants in aggregate root — Use Result<T> for validation
  6. Use domain events for side effects — Not direct service calls
  7. Make value objects immutable — No setters

License

MIT — see LICENSE for details.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on Trellis.DomainDrivenDesign:

Package Downloads
Trellis.Primitives

Infrastructure and ready-to-use implementations for primitive value objects in Domain-Driven Design. Includes base classes (RequiredString, RequiredGuid) with source generation, plus EmailAddress with RFC 5322 validation. Eliminates primitive obsession with strongly-typed domain primitives.

Trellis.Testing

Testing utilities and assertions for Trellis - FluentAssertions extensions, test builders, and fake implementations for Railway-Oriented Programming

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
3.0.0-alpha.99 0 3/4/2026
3.0.0-alpha.98 33 3/3/2026
3.0.0-alpha.95 44 3/2/2026
3.0.0-alpha.94 44 3/2/2026
3.0.0-alpha.93 43 3/1/2026
3.0.0-alpha.92 55 2/28/2026
3.0.0-alpha.83 40 2/27/2026