Quickstart¶
Choose the path that matches your first use case. Each path is designed to be copy-paste friendly with minimal changes to the template.
Option 1: add caching (5 minutes)¶
1) Install packages¶
dotnet add src/Application/Application.csproj package CleanArchitecture.Extensions.Caching
dotnet add src/Infrastructure/Infrastructure.csproj package CleanArchitecture.Extensions.Caching
2) Register caching services (Infrastructure)¶
3) Add the MediatR caching behavior (Application)¶
builder.Services.AddMediatR(cfg =>
{
cfg.RegisterServicesFromAssemblyContaining<Program>();
cfg.AddCleanArchitectureCachingPipeline();
});
4) Verify¶
Run the same query twice and confirm the second request is served from cache (debug logs show cache hit/miss).
Option 2: add multitenancy to an HTTP API (10 minutes)¶
1) Install packages¶
dotnet add src/Application/Application.csproj package CleanArchitecture.Extensions.Multitenancy
dotnet add src/Infrastructure/Infrastructure.csproj package CleanArchitecture.Extensions.Multitenancy
dotnet add src/Web/Web.csproj package CleanArchitecture.Extensions.Multitenancy.AspNetCore
2) Register services and middleware¶
using CleanArchitecture.Extensions.Multitenancy.AspNetCore;
builder.Services.AddCleanArchitectureMultitenancyAspNetCore(autoUseMiddleware: true);
var app = builder.Build();
If you prefer manual wiring, call app.UseCleanArchitectureMultitenancy() instead of enabling autoUseMiddleware.
Use manual wiring when you need claim- or route-based resolution so you can place the middleware after authentication or routing.
Template-friendly default: use header or host resolution. Route-based extraction requires routing middleware before the multitenancy middleware.
3) Add the multitenancy pipeline behaviors¶
builder.Services.AddMediatR(cfg =>
{
cfg.RegisterServicesFromAssemblyContaining<Program>();
cfg.AddCleanArchitectureMultitenancyPipeline();
});
Keep the multitenancy pipeline after authorization behaviors in the Jason Taylor template so authorization runs first.
4) Mark tenant-required endpoints¶
using CleanArchitecture.Extensions.Multitenancy.AspNetCore.Routing;
app.MapGroup("/tenants/{tenantId}")
.AddTenantEnforcement()
.RequireTenant();
Optional: add EF Core isolation¶
dotnet add src/Infrastructure/Infrastructure.csproj package CleanArchitecture.Extensions.Multitenancy.EFCore
using CleanArchitecture.Extensions.Multitenancy.EFCore;
using CleanArchitecture.Extensions.Multitenancy.EFCore.Options;
builder.Services.AddCleanArchitectureMultitenancyEfCore(options =>
{
options.Mode = TenantIsolationMode.SharedDatabase;
options.TenantIdPropertyName = "TenantId";
options.UseShadowTenantId = true;
});
Row-level filtering/enforcement defaults to shared database mode. For schema/database-per-tenant setups, explicitly set UseShadowTenantId, EnableQueryFilters, and EnableSaveChangesEnforcement to true if you want row-level defense-in-depth.
Next steps: - Installation guide - Caching extension - Multitenancy core - Multitenancy.AspNetCore - Multitenancy.EFCore