Nett.Core
2.2.0
dotnet add package Nett.Core --version 2.2.0
NuGet\Install-Package Nett.Core -Version 2.2.0
<PackageReference Include="Nett.Core" Version="2.2.0" />
<PackageVersion Include="Nett.Core" Version="2.2.0" />
<PackageReference Include="Nett.Core" />
paket add Nett.Core --version 2.2.0
#r "nuget: Nett.Core, 2.2.0"
#:package Nett.Core@2.2.0
#addin nuget:?package=Nett.Core&version=2.2.0
#tool nuget:?package=Nett.Core&version=2.2.0
Nett.Core
A lightweight .NET library providing foundational building blocks for Clean Architecture and Domain-Driven Design (DDD) in .NET 10+ applications.
๐ Features
- Entity & AggregateRoot: Base classes for domain entities with built-in domain event dispatching support.
- Enumeration: Type-safe, value-based enumerations.
- Repository Pattern: Repository base with support for paging, sorting, filtering, and projections.
- Specifications: Composite specification pattern for encapsulating query logic.
- Result & Error Handling: Functional-style
Result<T>monad for robust error handling without exceptions. - Paged Queries:
PagedRequestandPagedResponsefor efficient data retrieval. - Fluent Validations:
ParameterRuleBuilderfor parameter and model validation. - Domain Events: Simple event sourcing with
IDomainEventand dispatcher integration for EF Core.
Framework-agnostic core, with seamless integration for ASP.NET Core Minimal APIs and Entity Framework Core.
๐ฆ Installation
Add the package to your project:
dotnet add package Nett.Core
๐ Quick Start
1. Domain Entities & Aggregates
Inherit from Entity or AggregateRoot:
using Nett.Core.Domain;
using Nett.Core.Events;
public record PostCreated(string Title, DateTimeOffset CreatedAt) : IDomainEvent;
public class Post : AggregateRoot
{
public string Title { get; init; } = default!;
public string Content { get; init; } = default!;
public DateTimeOffset CreatedAt { get; init; } = DateTime.UtcNow;
public Post(string title, string content)
{
Title = title;
Content = content;
AddEvent(new PostCreated(Title, CreatedAt));
}
}
2. Base Repository
Implement your repository by overriding Queryable and SortMap:
using Microsoft.EntityFrameworkCore;
using Nett.Core.Domain;
using Nett.Core.Persistence;
public class PostRepository(AppDbContext db) : Repository<Post>, IPostRepository
{
protected override IQueryable<Post> Queryable => db.Posts;
protected override Dictionary<string, Expression<Func<Post, object>>> SortMap => new()
{
[nameof(Post.Title)] = p => p.Title,
[nameof(Post.CreatedAt)] = p => p.CreatedAt,
};
}
3. Paginated Queries with Minimal APIs
Define a paged request:
using Nett.Core.Models;
using Microsoft.EntityFrameworkCore;
public record PostResponse(string Title, string Content);
public sealed class PostRequest : PagedRequest<Post, PostResponse>
{
public string? Search { get; set; }
public override IReadOnlyCollection<Expression<Func<Post, bool>>> ToFilters()
{
var filters = new List<Expression<Func<Post, bool>>>();
if (!string.IsNullOrWhiteSpace(Search))
{
filters.Add(x => EF.Functions.ILike(x.Title, $"%{Search}%") ||
EF.Functions.ILike(x.Content, $"%{Search}%"));
}
return filters;
}
public override Expression<Func<Post, PostResponse>> ToProjection() =>
x => new PostResponse(x.Title, x.Content);
}
Use in endpoint:
app.MapGet("/", async (PostRepository repo, [AsParameters] PostRequest request, CancellationToken ct) =>
{
var response = await repo.Query(request, ct);
return response;
});
Supports ?page=1&limit=10&orderBy=Title&orderByDescending=true&search=GPT&thenBy=CreatedAt.
4. Domain Events with EF Core
public class AppDbContext(DbContextOptions<AppDbContext> options, IDomainEventsDispatcher dispatcher)
: DbContext(options)
{
public DbSet<Post> Posts { get; set; }
public override async Task<int> SaveChangesAsync(CancellationToken ct = default)
{
await dispatcher.DispatchEventsAsync(this, ct);
return await base.SaveChangesAsync(ct);
}
}
Register:
builder.Services.AddScoped<IDomainEventsDispatcher, DomainEventsDispatcher>();
builder.Services.AddScoped<IPostRepository, IPostRepository>();
5. Result & Error Handling
var result = Result.Success(new Post());
if (result.IsFailure)
{
return result.Error;
}
var result = ParameterRuleBuilder
.RuleFor(() => title)
.NotEmpty()
.MinLength(5)
.Build(() => new Post(title));
result.Match(
post => Console.WriteLine("Valid post {}", post.Title),
error => Console.WriteLine("Validation error {}", error.Errors.Message)
)
if (result.IsFailure)
{
return validated.Error;
}
var post = result.Value;
6. Fluent Parameter Validation
public static Result<Person> Create(string email, int age)
{
return ParameterRuleBuilder
.RuleFor(() => email).Email().NotEmpty()
.RuleFor(() => age).GreaterThan(18)
.Build(() => new Person(email, age));
}
๐ Examples
See the examples folder for a full Minimal API demo with PostgreSQL, EF Core, and domain events.
๐งช Testing
Comprehensive unit tests in /tests. Run with:
dotnet test
๐ License
MIT License - see LICENSE
๐ Acknowledgments
Built with โค๏ธ for .NET developers embracing Clean Architecture and DDD.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net11.0 is compatible. |
-
net11.0
- Microsoft.EntityFrameworkCore (>= 11.0.0-preview.2.26159.112)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.2.0 | 144 | 4/12/2026 |
| 2.1.0 | 265 | 3/31/2026 |
| 2.0.0 | 313 | 12/6/2025 |
| 2.0.0-beta.2 | 125 | 11/23/2025 |
| 2.0.0-beta.1 | 228 | 11/21/2025 |
| 1.0.3 | 362 | 7/10/2025 |
| 1.0.2 | 223 | 7/10/2025 |
| 1.0.1 | 231 | 7/10/2025 |
| 1.0.0 | 235 | 6/17/2025 |
| 1.0.0-alpha.6 | 150 | 6/16/2025 |
| 1.0.0-alpha.5 | 218 | 5/23/2025 |
| 1.0.0-alpha.4 | 152 | 5/22/2025 |
| 1.0.0-alpha.3 | 118 | 4/18/2025 |
| 1.0.0-alpha.2 | 200 | 4/17/2025 |
| 1.0.0-alpha.1 | 194 | 4/17/2025 |
| 0.15.1 | 398 | 11/27/2024 |
| 0.15.0 | 204 | 11/24/2024 |
| 0.14.0 | 201 | 11/23/2024 |
| 0.13.1 | 335 | 8/8/2024 |
| 0.13.0 | 230 | 8/8/2024 |