Shared .NET service infrastructure — consumed as a git submodule, not from NuGet.
Three libraries that most of my .NET services are built on. They are deliberately not published to NuGet: they are opinionated, they move with the services that use them, and a submodule lets a change land in a consumer the same day it is written rather than a release later.
| Module | Namespace | What it is |
|---|---|---|
platform/ |
CoreLibs.* |
Configuration, startup orchestration, CQRS, persistence, jobs, storage, identity, observability |
live-config/ |
CoreLibs.LiveConfig.* |
Hot-reloadable runtime configuration from JSON, Google Sheets, Redis, MongoDB and Postgres |
localization/ |
CoreLibs.Localization.* |
Database-backed runtime localization with LiveConfig and Telegram adapters |
Targets net10.0. Building needs the .NET 10 SDK (pinned in global.json).
Add the repository as a submodule, then reference the projects you need by relative path.
git submodule add https://github.com/deniscuciuc/dotnet-libs libs/dotnet-libs
git submodule update --init --recursive<ItemGroup>
<ProjectReference Include="libs/dotnet-libs/platform/src/CoreLibs.Startup/CoreLibs.Startup.csproj" />
<ProjectReference Include="libs/dotnet-libs/platform/src/CoreLibs.MongoDB/CoreLibs.MongoDB.csproj" />
<ProjectReference Include="libs/dotnet-libs/live-config/src/CoreLibs.LiveConfig.Startup/CoreLibs.LiveConfig.Startup.csproj" />
</ItemGroup>Pin the submodule to a tag rather than tracking main if you want reproducible builds:
git -C libs/dotnet-libs checkout v1.0.0To update later:
git submodule update --remote libs/dotnet-libsThese packages are shaped around one set of conventions — an ordered IStartup pipeline, a
YAML configuration layout, a MongoDB repository pattern. Publishing them would imply an API
stability promise that would slow the services down for no one's benefit. If you want a
standalone, versioned, dotnet add package library from this account, see
TeleForge,
FluentDocs and
Rulebook instead — none of those depends on this
repository.
Configuration, host startup, and the infrastructure a service usually needs on day one.
var builder = WebApplication.CreateBuilder(args);
builder.AddCoreConfiguration(); // YAML pipeline + convention-bound typed options
builder.Host.UseCoreSerilog();
builder.Services.AddCoreMongoDBStartup();
builder.Services.AddCoreCqrsFromAssemblyOf<Program>();
var app = builder.Build();
app.UseCoreCorrelationId();
app.MapCoreMetrics();
await app.RunWithStartupAsync(); // ordered startup tasks run before the host serves| Project | Purpose |
|---|---|
CoreLibs.Configuration |
YAML configuration pipeline with convention-based typed options |
CoreLibs.Startup |
Ordered startup orchestration and fail-fast guards before Host.RunAsync |
CoreLibs.Domain |
Entity, domain events, auditing and soft-delete primitives |
CoreLibs.CQRS |
MediatR + FluentValidation + ErrorOr request pipeline with caching behaviours |
CoreLibs.Cache |
Cache abstractions shared by the Redis and Mongo layers |
CoreLibs.MongoDB |
Repository pattern, indexes, migrations, seeding, CAS/actor support |
CoreLibs.Postgres |
EF Core and Npgsql registration with naming conventions |
CoreLibs.Redis |
ICache over StackExchange.Redis, plus composite caching |
CoreLibs.MQ |
RabbitMQ via MassTransit |
CoreLibs.Identity |
JWT plus Firebase, Auth0, Telegram-login and internal-secret validators |
| `CoreLibs.Storage[.Disk | .S3]` |
| `CoreLibs.Jobs[.Hangfire | .Quartz]` |
CoreLibs.ErrorHandling |
Exception middleware and ErrorOr → IResult mapping |
CoreLibs.HealthCheck, .Metrics, .Serilog, .Sentry |
Observability |
CoreLibs.Swagger.Theme |
Swashbuckle registration with a dark theme |
Every component ships a matching *.Startup project that registers it into the startup
orchestrator. Docs: platform/docs/.
Configuration that changes while the process is running, without a redeploy.
Sources (IConfigSource) produce snapshots, IConfigStore versions them, IConfigDistributor
fans changes across instances over Redis pub/sub, and IConfigApplier/IConfigHook
implementations — discovered by attribute — apply them into typed caches.
| Project | Purpose |
|---|---|
CoreLibs.LiveConfig.Abstractions |
Contracts and attributes |
CoreLibs.LiveConfig |
Engine, hashing and snapshot pipeline |
CoreLibs.LiveConfig.Json |
JSON and YAML file sources |
CoreLibs.LiveConfig.GSheet |
Google Sheets source, entity API and schema mapping |
CoreLibs.LiveConfig.Redis |
Cross-instance distribution |
CoreLibs.LiveConfig.Store.MongoDB, .Store.Postgres |
Versioned persistence with retention |
CoreLibs.LiveConfig.Startup |
Auto-discovery and preload |
CoreLibs.LiveConfig.Hosting |
Standalone config-manager host with MassTransit |
CoreLibs.LiveConfig.Observability |
OpenTelemetry metrics |
Docs: live-config/docs/. Runnable example:
live-config/examples/.
Runtime i18n backed by a database rather than resx, so translators change strings without a build.
services.AddCoreLocalization(o =>
{
o.DefaultCulture = "en";
o.FallbackChain = ["ro", "en"];
});
// later
localizer.Get("cart.empty", "ro");
localizer.GetPlural("cart.items", "ro", count: 3);| Project | Purpose |
|---|---|
CoreLibs.Localization |
Dependency-free contracts and value types |
CoreLibs.Localization.Runtime |
Localizer, atomically-swapped cache, interpolation, CLDR pluralization |
CoreLibs.Localization.Cache |
Redis decorator for cross-instance sync and cold start |
CoreLibs.Localization.Store.MongoDB, .Store.Postgres |
Persistence |
| `CoreLibs.Localization.LiveConfig[.Json | .GSheet]` |
CoreLibs.Localization.Telegram |
Language detection from a Telegram user |
Docs: localization/docs/.
dotnet restore CoreLibs.slnx
dotnet build CoreLibs.slnx -c Release
dotnet test CoreLibs.slnx -c ReleaseThe integration suites use Testcontainers and need a working Docker or Podman socket. They start MongoDB, Postgres and Redis themselves — no local services required.
Two dependencies are worth knowing about before you ship something built on this:
- Hangfire (
CoreLibs.Jobs.Hangfire) is LGPL-3.0 with a commercial option. Using it as an unmodified NuGet package in a closed-source service is generally fine; redistributing a modified Hangfire is not. If that is a problem, useCoreLibs.Jobs.Quartzinstead — Quartz.NET is Apache-2.0 and theIJobSchedulerabstraction is the same either way. - MediatR (
CoreLibs.CQRS) is pinned to 12.1.1, the last Apache-2.0 release. v13 moved to a paid commercial license. The pin is deliberate; do not let a dependency update cross it without a decision.
Everything else is MIT, Apache-2.0 or BSD.
Releases are git tags, not packages — see docs/release-process.md.
See CONTRIBUTING.md, CODE_OF_CONDUCT.md and SECURITY.md.