DKNet is a suite of independent .NET 10 NuGet packages for building enterprise applications around
Domain-Driven Design and Onion Architecture. There is no framework to adopt wholesale and no single
AddDKNet() call: each package registers itself and can be used on its own, so you pull in only what a given
DbContext, API, or worker actually needs.
28 packages are published to NuGet. One more, Aspire.Hosting.ServiceBus, is source-only in this repository
(<IsPackable>false</IsPackable>) and documented anyway — it is an Aspire shared project you reference from an
AppHost directly. DKNet.EfCore.Repos and DKNet.EfCore.Repos.Abstractions, the older generic-repository
packages, were removed outright; see Migrating-Repos-To-Specifications
if you are upgrading off them.
- Getting Started Guide — prerequisites, installation, and a first working setup
- Configuration & Setup — how configuration composes across packages
- Architecture Guide — the rings, what depends on what, and the two end-to-end paths
- Agent skills (
dknet-skills) — install withnpx skills add baoduy/DKNetorclaude plugin install dknet-skills@dknetso your coding agent knows every package
- API Reference — index into the per-package API documentation
- Examples & Recipes — runnable implementation examples
- FAQ — common questions and troubleshooting
- Changelog — version history and release notes
- Migration Guide — upgrading between versions and off retired packages
- Contributing Guide — how to contribute to the project
- Testing Strategy — test stack and coverage targets
- Security Policy — supported versions and vulnerability reporting
Sorted by the problem you have, not by namespace. Follow the link for the full API and gotchas.
| I need to… | Package |
|---|---|
| Give entities identity, audit fields, and a domain-event queue | DKNet.EfCore.Abstractions |
Have EF Core discover my IEntityTypeConfiguration<T> classes, apply global filters, seed data, use GUID v7 keys or SQL sequences |
DKNet.EfCore.Extensions |
| Query and persist without hand-rolling a repository per entity | DKNet.EfCore.Specifications |
| Build a search/filter predicate whose criteria are only known at runtime | DKNet.EfCore.Specifications — Dynamic Predicate Builder |
Run my own code before and after every SaveChanges |
DKNet.EfCore.Hooks |
| Let a domain method raise an event that other code reacts to after the write commits | DKNet.EfCore.Events |
| Record who changed which field, with sensitive values redacted | DKNet.EfCore.AuditLogs |
| Stop one tenant or owner from reading another's rows | DKNet.EfCore.DataAuthorization |
| Encrypt a column without changing the queries that read it | DKNet.EfCore.Encryption |
| Stop hand-writing DTOs that mirror entities | DKNet.EfCore.DtoGenerator |
| Check for or create a table at runtime, whatever the relational provider | DKNet.EfCore.Relational.Helpers |
| Replace MediatR with an in-process command/query bus (no EF Core) | DKNet.SlimBus.Extensions |
Separate commands from queries and stop calling SaveChangesAsync in handlers |
DKNet.SlimBus.Extensions.EfCore |
| Generate CRUD requests, handlers, and endpoints from an attributed entity member | DKNet.SlimBus.Generators |
Map minimal-API endpoint groups by convention and turn a Result into ProblemDetails |
DKNet.AspCore.Extensions |
Make a POST/PUT/PATCH safe for a client to retry |
DKNet.AspCore.Idempotency on its own for local development, plus one store package for deployed traffic |
| Run a job exactly once at start-up, before traffic arrives | DKNet.AspCore.Tasks |
| Store files without binding the application to one cloud | DKNet.Svc.BlobStorage.Abstractions plus one adapter |
| Encrypt, sign, or hash a value in ordinary application code | DKNet.Svc.Encryption |
| Render Markdown or HTML to a PDF file | DKNet.Svc.PdfGenerators |
| Fill bracketed tokens in a template string from an object or a dictionary | DKNet.Svc.Transformation |
| Generate a password, token, or other secret | DKNet.RandomCreator |
Scan assemblies for types, or reach for a string/enum/DateTime/reflection helper |
DKNet.Fw.Extensions |
| Give a local Aspire AppHost its own Azure Service Bus emulator | Aspire.Hosting.ServiceBus (source-only) |
Foundation utilities that sit at the bottom of the dependency graph and pull in nothing else from DKNet.
- DKNet.Fw.Extensions — framework-agnostic reflection, type, string, enum and DI-inspection helpers, plus fluent assembly/type scanning (
TypeExtractors) - DKNet.RandomCreator — cryptographically secure random string and character generation for passwords, tokens, and other secrets
Entity base classes, the specification pattern, and the SaveChanges interceptor pipeline everything else hangs off.
- DKNet.EfCore.Abstractions — the persistence-agnostic vocabulary every other
DKNet.EfCore.*package builds on: entity base classes, domain-event contracts, and the attributes that steer audit, sequence, and mapping behaviour - DKNet.EfCore.Extensions — the wiring layer: convention-based entity configuration, global query filters, data seeding, GUID v7 keys, SQL sequences, and the
SnapshotContextthe save hooks are built on - DKNet.EfCore.Specifications — filter, includes, and order-by as one reusable object, executed through a single non-generic
IRepositorySpec, plus a runtime dynamic predicate builder. The current, supported way to query and persist - DKNet.EfCore.Hooks — a pluggable before/after-
SaveChangesinterceptor pipeline: one shared interceptor perDbContexttype plus a pair of interfaces you implement - DKNet.EfCore.Events — dispatches domain events raised by entities during
SaveChanges, so a domain method never references a publisher or a bus - DKNet.EfCore.AuditLogs — captures a structured, field-level change record for every created, updated, or deleted entity and hands the batch to publishers you register
- DKNet.EfCore.DataAuthorization — row-level, ownership-based authorization: an automatic global query filter on reads plus
SaveChanges-time owner stamping on writes - DKNet.EfCore.Encryption — transparent, column-level encryption for
stringproperties, applied at the database boundary via a standardValueConverter - DKNet.EfCore.DtoGenerator — a Roslyn incremental source generator that emits DTO properties from an entity type at compile time
- DKNet.EfCore.Relational.Helpers — four
DbContextextension methods for relational bookkeeping EF Core does not expose: table creation, connection access, table-name resolution, and table-existence checks
SlimMessageBus integration: CQRS contracts, automatic save, and the CRUD source generator.
- DKNet.SlimBus.Extensions — EF-free fluent command/query/event interfaces and a one-call MediatR-replacement setup
- DKNet.SlimBus.Extensions.EfCore — automatic
SaveChangesafter a successful write, and domain events forwarded onto the bus - DKNet.SlimBus.Generators — emits a whole CRUD vertical slice (request records, handlers, endpoint registration) from
[CrudCreate]/[CrudUpdate]/[CrudAction]-attributed entity members
Application-level services with no dependency on the EF Core packages.
- DKNet.Svc.BlobStorage.Abstractions — provider-agnostic
IBlobServicecontract and shared model types - DKNet.Svc.BlobStorage.AwsS3 — AWS S3 adapter that also works against S3-compatible services such as MinIO and Cloudflare R2
- DKNet.Svc.BlobStorage.AzureStorage — Azure Blob Storage adapter backed by
Azure.Storage.Blobs - DKNet.Svc.BlobStorage.Local — local-filesystem adapter that stores blobs under a configured root folder with path-traversal protection
- DKNet.Svc.Encryption — explicitly-invoked cryptography: AES-GCM and RSA encryption, RSA signing, HMAC and SHA hashing, and Base64/Base64URL helpers
- DKNet.Svc.PdfGenerators — converts HTML or Markdown into a PDF using headless Chromium (PuppeteerSharp) and Markdig, with page layout, header/footer, and margin control
- DKNet.Svc.Transformation — fills bracketed tokens in a template string from plain objects or string dictionaries by reflection
Start-up orchestration, minimal-API glue, and idempotency for web and API workloads.
- DKNet.AspCore.Extensions — host-populated request members, discovered and versioned endpoint groups, verb-to-command mappers, generic list/read/delete endpoints, and
FluentResults-to-IResultconversion - DKNet.AspCore.Tasks — implement
IBackgroundTask, register it, and oneBackgroundServiceruns every registered task once when the host starts - DKNet.AspCore.Idempotency — an
IEndpointFilterthat recognises a client-supplied idempotency key, blocks the same operation from running twice, and replays or rejects the retry - DKNet.AspCore.Idempotency.MsSqlStore — SQL Server-backed key store
- DKNet.AspCore.Idempotency.NpgsqlStore — PostgreSQL-backed key store
- DKNet.AspCore.Idempotency.RedisStore — Redis-backed key store using
SET NXreservation and native key expiry, with no schema or migrations - DKNet.AspCore.Idempotency.Relational — the shared EF Core building blocks the two relational stores derive from. Not referenced directly by application code
Infrastructure orchestration helpers for .NET Aspire AppHost projects.
- Aspire.Hosting.ServiceBus — adds the Azure Service Bus emulator as a resource inside an Aspire AppHost, so local work needs no shared cloud namespace. Source-only: it sets
<IsPackable>false</IsPackable>, so reference the project from your AppHost rather than a NuGet package
Every ring of the onion is a separate package, and every dependency points inward. The Architecture Guide walks the same picture in detail, adds the package dependency graph, and traces a request and a domain event end to end.
- Dependency inversion — inner rings never reference outer ones; the arrows above are real
ProjectReferenceentries insrc/. - Separation of concerns — one package, one responsibility, and no package that only exists to aggregate others.
- Domain-centricity — business rules live in entity methods;
DKNet.EfCore.Abstractionsis the only package a domain model has to see. - Event-driven where it helps — domain events are queued on the entity and dispatched after the write commits, so a domain method never talks to a bus.
- Specifications, not a repository per entity — one injected
IRepositorySpecserves every entity type; the entity comes from the specification passed to each call.
- Pick the packages you need — start from the Which package do I need? table above.
- Read the ring it lives in — the Architecture Guide explains what a package can and cannot depend on.
- Wire it up — Configuration & Setup covers the four registration conventions the packages share.
- Copy a working example — Examples & Recipes, or the SlimBus.ApiEndpoints template in the DKNet.Templates repository.
Corrections and additions are welcome. Open an issue describing the problem, or send a pull request that follows the structure and voice of the surrounding pages — the canonical page structure is the Package Documentation Template; see also the Contributing Guide.
Every claim on these pages should be traceable to src/, a test, or a config file. If you find one that
is not, that is a bug worth reporting in the DKNet repository.