DKNet is not a framework you adopt wholesale — it is 28 independent NuGet packages. Getting started means picking the two or three you need and wiring them up. This page covers the prerequisites, the smallest setup that actually runs, and where to go next.
net10.0 (the two Roslyn source generators,
DKNet.EfCore.DtoGenerator and DKNet.SlimBus.Generators, target netstandard2.0 so the compiler can load
them — that does not change what your app targets), and src/global.json pins SDK 10.0.0 with
rollForward: latestMajor.DKNet.EfCore.Relational.Helpers and the two relational
idempotency stores.The Which package do I need? table maps problems to packages. A typical DDD-style API starts with four:
# Entity base classes and the domain-event contracts
dotnet add package DKNet.EfCore.Abstractions
# Entity configuration discovery, global query filters, seeding, GUID v7 keys
dotnet add package DKNet.EfCore.Extensions
# Querying and persistence through IRepositorySpec
dotnet add package DKNet.EfCore.Specifications
# CQRS handlers with automatic SaveChanges
dotnet add package DKNet.SlimBus.Extensions
Add more as the need appears — nothing above depends on the others being present, and no package needs a companion “core” package.
DKNet.EfCore.ReposandDKNet.EfCore.Repos.Abstractionswere removed and were never published to NuGet.dotnet add packagewill not find them. UseDKNet.EfCore.Specifications— see Migrating-Repos-To-Specifications if you are upgrading off them.
Derive from AuditedEntity (Guid-keyed, with created/updated tracking and a domain-event queue) or from plain
Entity if you do not want the audit fields. Change state through methods, not public setters:
using DKNet.EfCore.Abstractions.Entities;
public class Product : AuditedEntity
{
private Product() { } // EF Core
public static Product Create(string name, decimal price, string createdBy)
{
var product = new Product { Name = name, Price = price, IsActive = true };
product.SetCreatedBy(createdBy);
return product;
}
public string Name { get; private set; } = string.Empty;
public decimal Price { get; private set; }
public bool IsActive { get; private set; }
public void Deactivate(string updatedBy)
{
IsActive = false;
SetUpdatedBy(updatedBy);
}
}
AddDbContextWithHook<TDbContext> registers the DbContext and the shared hook interceptor in one call;
UseAutoConfigModel<TContext>() is a DbContextOptionsBuilder<TContext> extension, so it goes here rather than
in OnModelCreating:
using DKNet.EfCore.Hooks; // AddDbContextWithHook
using DKNet.EfCore.Specifications; // AddSpecRepo
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContextWithHook<AppDbContext>(options => options
.UseSqlServer(builder.Configuration.GetConnectionString("Default")!)
// Discovers every IEntityTypeConfiguration<T> in AppDbContext's assembly
.UseAutoConfigModel<AppDbContext>());
// One IRepositorySpec serves every entity type in the context
builder.Services.AddSpecRepo<AppDbContext>();
var app = builder.Build();
app.Run();
AddDbContextWithHook is only needed when something hooks into SaveChanges — domain events, audit logs, or
ownership stamping. If none of those are in play, a plain AddDbContext<AppDbContext> works and
UseAutoConfigModel<AppDbContext>() still applies.
A Specification<TEntity> is configured from its constructor and carries the filter, includes, and ordering as
one reusable object:
using DKNet.EfCore.Specifications.Definitions;
using DKNet.EfCore.Specifications.Extensions;
using DKNet.EfCore.Specifications.Repositories;
public sealed class ActiveProductsSpec : Specification<Product>
{
public ActiveProductsSpec()
{
WithFilter(p => p.IsActive);
AddOrderBy(p => p.Name);
}
}
public sealed class Catalogue(IRepositorySpec repo)
{
public Task<IList<Product>> ActiveAsync(CancellationToken cancellationToken = default) =>
repo.ToListAsync(new ActiveProductsSpec(), cancellationToken);
}
Every ring of the onion is a separate package and every dependency points inward. The Architecture Guide has the full picture, including the package dependency graph and two end-to-end walkthroughs (an HTTP request and a domain event):
| Goal | Read next |
|---|---|
| A CRUD API with commands and queries separated | DKNet.SlimBus.Extensions, then Examples |
| Side effects that run after a write commits | DKNet.EfCore.Events, then A domain event end to end |
| Row-level isolation between tenants or owners | DKNet.EfCore.DataAuthorization, then Examples |
A POST a client can safely retry |
DKNet.AspCore.Idempotency on its own for local development, plus one store package for deployed traffic |
| Files in Azure, S3, or on disk behind one interface | DKNet.Svc.BlobStorage.Abstractions |