How Elarion differs from ASP.NET Core
A side-by-side look at where Elarion's conventions diverge from idiomatic ASP.NET Core, and the trade-off you accept.
Elarion is intentionally not a thin wrapper around the default ASP.NET Core style. It chooses a more application-centric architecture where modules and handlers are the source of truth, while the ASP.NET Core host becomes a composition and transport shell.
| Topic | Idiomatic ASP.NET Core | Elarion |
|---|---|---|
| Registration | Explicit services.AddScoped<…>(), endpoint maps, and feature wiring in Program.cs. | Source-generated auto-registration from handler, validator, module, and RPC attributes. Explicit registration remains for infrastructure. |
| Application shape | Controllers, Minimal API lambdas, or endpoint classes are the use-case boundary. | IHandler<TRequest, TResponse> is the use-case boundary; transport adapters call handlers. |
| Modularity | Folder/project organization plus manually maintained AddXyz() methods. | First-class modules with [AppModule]: feature flags, ordering, handler/validator aggregation, endpoint hooks, JSON metadata hooks. |
| Cross-cutting behavior | Middleware, endpoint filters, MVC filters, MediatR behaviors, or nested services. | Generated decorator pipelines wrap handlers in a deterministic order chosen by assembly, module, or handler. |
| Discovery | Runtime reflection scanning for validators, handlers, controllers, endpoint modules. | Compile-time source generation for deterministic startup, AOT friendliness, and inspectable code. |
| Host responsibilities | The host often knows every feature and registers most feature services. | The host owns platform capabilities, middleware, auth, telemetry, database setup, and transports; modules own composition. |
| Serialization metadata | Global JSON options plus reflection fallback. | Modules contribute JsonSerializerContext resolvers following the module boundary. |
| EF Core model wiring | Hand-written DbSet<T> and ApplyConfigurationsFromAssembly(…). | Optional generator with interface-first [GenerateDbSets], explicit [DbEntity], optional scopes, and direct configuration calls. |
| Background work | Individual BackgroundService loops own their timers, overlap, logging, and cancellation. | Source-generated scheduled jobs share one scheduler with typed invocation, explicit overlap, TimeProvider, and telemetry. |
| Error model | Exceptions, ProblemDetails, action results, or ad-hoc DTOs. | Handlers return Result<T> with transport-agnostic AppError; the host maps errors per transport. |
| Transport | HTTP REST is the default API. | JSON-RPC is a first-class optional transport, kept outside the core package. |
| Client contracts | Frontends hand-write DTOs or ad-hoc REST helpers. | JSON-RPC clients consume generated TypeScript/Zod artifacts and a portable fetch client from the schema. |
The trade-off
The main cost is that you accept conventions. Handler names, nested Command/Query and
Response types, module namespace containment, and pipeline attributes matter because the generators
use them. In exchange you get:
- less host boilerplate,
- inherent modularity,
- fewer runtime scans and faster, more predictable startup,
- a clearer separation between application policy and host mechanics.
If your project benefits from that structure — a modular application or service, AOT goals, a typed .NET↔TypeScript contract, in-process background work — the conventions pay for themselves. If you need maximum freedom in how each endpoint is shaped, idiomatic ASP.NET Core may fit better. The introduction covers when Elarion is a good fit.