Odex.AspNetCore.Clarc.Domain 0.2.0

dotnet add package Odex.AspNetCore.Clarc.Domain --version 0.2.0
                    
NuGet\Install-Package Odex.AspNetCore.Clarc.Domain -Version 0.2.0
                    
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="Odex.AspNetCore.Clarc.Domain" Version="0.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Odex.AspNetCore.Clarc.Domain" Version="0.2.0" />
                    
Directory.Packages.props
<PackageReference Include="Odex.AspNetCore.Clarc.Domain" />
                    
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 Odex.AspNetCore.Clarc.Domain --version 0.2.0
                    
#r "nuget: Odex.AspNetCore.Clarc.Domain, 0.2.0"
                    
#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 Odex.AspNetCore.Clarc.Domain@0.2.0
                    
#: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=Odex.AspNetCore.Clarc.Domain&version=0.2.0
                    
Install as a Cake Addin
#tool nuget:?package=Odex.AspNetCore.Clarc.Domain&version=0.2.0
                    
Install as a Cake Tool

Odex.AspNetCore.Clarc.Domain

NuGet NuGet Downloads CI License

Reusable domain-layer building blocks for .NET: aggregates, domain events, specifications, guard policies, persistence-oriented repository contracts, and transaction abstractions. The public API is fully documented with XML comments for IntelliSense and NuGet. No ASP.NET Core or EF Core dependency—this assembly targets plain net9.0 so you can use it from any host or stack.


Table of contents


About

Odex.AspNetCore.Clarc.Domain is part of the CLARC family of packages. It gives you shared types and interfaces so domain code stays consistent across solutions: typed aggregate roots, optional lifecycle state, composable query predicates (Specification<T>), lightweight aggregate events (raised in the domain, dispatched in your infrastructure), guard-style checks (BasePolicy<T>), and async repository contracts you implement against your chosen store.

The package is opinionated about structure, not about frameworks. You wire dependency injection, ORMs, outboxes, and mediators in Application and Infrastructure—not in this library.


Installation

dotnet add package Odex.AspNetCore.Clarc.Domain

Pin a version when you need a reproducible build:

dotnet add package Odex.AspNetCore.Clarc.Domain --version 0.2.0

Requirements

Item Version
Target framework net9.0
.NET SDK 9.x (for development and consumption aligned with the target)

This library has no NuGet dependencies at runtime beyond the .NET runtime. The package build references Microsoft.SourceLink.GitHub (private asset) so consumers get GitHub-backed source debugging in supported IDEs. The same build emits XML API documentation for all public types and members (see API documentation). Your Infrastructure project references EF Core, Dapper, or other stacks as needed.

To build and test this repository locally, see CONTRIBUTING.md.


How it fits in CLARC / clean architecture

Layer Responsibility Typical CLARC package
Domain Entities, value objects, domain services, invariants, aggregate events (raised, not dispatched) This package
Application Use cases, commands/queries, handlers, orchestration Odex.AspNetCore.Clarc.Application (your solution)
Infrastructure Persistence, external APIs, event dispatch, DI registrations Odex.AspNetCore.Clarc.Infrastructure (your solution)

Repository interfaces (IAggregateRepository<,>) use IQueryable / Expression<> so implementations can translate predicates to SQL (for example with EF Core). That is a deliberate trade-off: the contract stays persistence-oriented while remaining store-agnostic at compile time.


Capabilities

Area Types (summary)
Aggregates BaseAggregate<TId> — identity, audit timestamps, in-memory domain event list. StatefulAggregate<TId> — activation and soft-delete flags with timestamps.
Events IAggregateEvent, AggregateEvent — correlation id and OccurredOn; collect with AddEvent, read with ListEvents, clear after dispatch in infrastructure.
Specifications Specification<T> with And / Or / Not; ToExpression() for providers that compile LINQ expressions.
Policies IBasePolicy<T>, BasePolicy<T>RequireNotNull, RequireNotNullNorEmpty, RequireNullOrEmpty, RequireTrue / RequireFalse, etc.
Repositories IBaseRepositorySaveChangesAsync, ExecuteInTransactionAsync. IAggregateRepository<TEntity,TId> — async reads/writes, includes, attach helpers.
Transactions ITransactionContext — cooperative rollback signalling for unit-of-work implementations.
Exceptions DomainException, PolicyViolationException, EntityNotFoundException, ConcurrencyException, InvalidEntityStateException with ExceptionType.
Value objects / DTO markers BaseValueObject, BaseRequest, BaseResponse, PagedRequest, PagedResponse<T>, BaseData.

API documentation

The public API is documented with XML Doc Comments (/// summaries, parameters, type parameters, return values, and documented exceptions where relevant). The project enables GenerateDocumentationFile, so each NuGet release ships Odex.AspNetCore.Clarc.Domain.xml next to the assembly. That file powers:

  • IDE IntelliSense (Visual Studio, Rider, VS Code with C# Dev Kit)
  • NuGet.org API reference and tooltips for consumers

If you extend or change public types, keep documentation in sync; see CONTRIBUTING.md.


Examples

Aggregate and policy

public class Product : StatefulAggregate<Guid>
{
    public string Name { get; private set; } = string.Empty;

    public void Rename(string newName)
    {
        var policy = new BasePolicy<string>();
        policy.RequireNotNullNorEmpty(newName);

        Name = newName;
        MarkModified();
        AddEvent(new ProductRenamedEvent(Id, newName));
    }
}

Define ProductRenamedEvent as a type implementing IAggregateEvent (or inheriting AggregateEvent with extra payload properties).

Specification

public sealed class ActiveUsersSpec : Specification<User>
{
    public override Expression<Func<User, bool>> ToExpression()
        => u => u.IsActive;
}

// Compose and pass the expression to your repository implementation
var spec = new ActiveUsersSpec().And(new UserNameContainsSpec("alex"));
await repository.ListAsync(spec.ToExpression(), cancellationToken);

Application service with AggregateService

AggregateService depends on IBaseRepository. Your aggregate repository implementation should implement both IAggregateRepository<T, TId> and the same unit-of-work boundary as IBaseRepository.

public sealed class ProductService(IAggregateRepository<Product, Guid> products)
    : AggregateService(products)
{
    public async Task<Product> CreateAsync(string name, CancellationToken cancellationToken = default)
    {
        var product = new Product(name);
        await products.AddAsync(product, cancellationToken);
        await SaveRepositoryChangesAsync(cancellationToken);
        return product;
    }
}

Transaction boundary

await ExecuteInRepositoryTransactionAsync(async () =>
{
    await repositoryA.AddAsync(entity, cancellationToken);
    await repositoryB.UpdateAsync(other, cancellationToken);
    return true;
}, cancellationToken);

Commit vs rollback semantics are defined by your IBaseRepository / infrastructure implementation.

Composition root (dependency injection)

Register your implementations where the application starts (ASP.NET Core minimal API host, generic host, test fixture, etc.):

builder.Services.AddScoped<IProductRepository, ProductRepository>();
builder.Services.AddScoped<ProductService>();

Namespaces

Namespace Role
Odex.AspNetCore.Clarc.Domain.Aggregates BaseAggregate<>, StatefulAggregate<>
Odex.AspNetCore.Clarc.Domain.Constants ExceptionType
Odex.AspNetCore.Clarc.Domain.Contexts ITransactionContext
Odex.AspNetCore.Clarc.Domain.DTOs BaseData marker
Odex.AspNetCore.Clarc.Domain.Events IAggregateEvent, AggregateEvent
Odex.AspNetCore.Clarc.Domain.Exceptions Domain exception hierarchy
Odex.AspNetCore.Clarc.Domain.Policies IBasePolicy<>, BasePolicy<>
Odex.AspNetCore.Clarc.Domain.Repositories IBaseRepository, IAggregateRepository<,>
Odex.AspNetCore.Clarc.Domain.Services IBaseService, BaseService, IAggregateService, AggregateService
Odex.AspNetCore.Clarc.Domain.Specifications Specification<>, combinators, ReplaceParameterVisitor
Odex.AspNetCore.Clarc.Domain.ValueObjects BaseValueObject; Requests / Responses (e.g. PagedRequest, PagedResponse<>)

Upgrading

See the changelog for version history and breaking changes. A copy also lives at the repository root as CHANGELOG.md for forks and offline docs.

0.1.x → 0.2.0 (summary):

  • DeleteByAccessIdAsync was removed from IAggregateRepository<,>.
  • Read methods that accept includeBuilder gained an optional trailing CancellationToken.

Contributing

See CONTRIBUTING.md for setup, pull-request expectations, and versioning notes.


Community


License

This project is released under the MIT License.

Copyright (c) Asen O'Shabi.


Resource URL
NuGet Gallery https://www.nuget.org/packages/Odex.AspNetCore.Clarc.Domain
Changelog https://github.com/o-shabi/odex-clarc-domain-aspnetcore/blob/main/CHANGELOG.md
Contributing CONTRIBUTING.md (includes XML documentation for contributors)
Security SECURITY.md
Source / issues https://github.com/o-shabi/odex-clarc-domain-aspnetcore
Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  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.
  • net9.0

    • No dependencies.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Odex.AspNetCore.Clarc.Domain:

Package Downloads
Odex.AspNetCore.Clarc.Infrastructure

Multi-purpose CLARC infrastructure for .NET 9: LINQ query builders, Domain-aligned paging, specification filters, transaction support, and typed infrastructure exceptions. Bring your own ORM or LINQ provider.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.2.0 111 5/13/2026
0.1.2 116 4/28/2026
0.1.1 84 4/28/2026
0.1.0 92 4/28/2026