Module Lifecycle & Modularity Engine
During the scaling of an enterprise Modular Monolith, a frequent architectural smell is the uncontrolled growth of Program.cs. When hundreds of services and endpoints are wired inline within the host entrypoint, initialization order becomes fragile, and implicit dependencies cause runtime failures.
BitzOrcas.Modern resolves this via BitzOrcas.Modularity and the BitzOrcas.Modularity.Generator source generator, encapsulating each business domain into an autonomous module definition with explicit dependencies and automated lifecycle management.
1. Module Definition Contract: IModuleDefinition and [DependsOn]
Each module defines a module entry class implementing IModuleDefinition in its Contracts or Application root, declaring explicit dependencies using [DependsOn]:
using System;using BitzOrcas.Modularity;using Microsoft.AspNetCore.Builder;using Microsoft.Extensions.Configuration;using Microsoft.Extensions.DependencyInjection;
namespace BitzOrcas.Modules.Litigation;
/// <summary>/// Litigation module definition declaring strong prerequisites on Identity and Notifications./// </summary>[DependsOn(typeof(BitzOrcas.Platform.Identity.Contracts.IdentityModule))][DependsOn(typeof(BitzOrcas.Platform.Notifications.Contracts.NotificationsModule))]public sealed class LitigationModule : IModuleDefinition{ public string ModuleName => "Litigation";
public int Order => 100;
/// <summary> /// Service registration phase: configure repositories, domain services, and external clients. /// </summary> public void ConfigureServices(IServiceCollection services, IConfiguration configuration) { // 1. Bind module-specific configuration services.AddOptions<LitigationOptions>() .Bind(configuration.GetSection("Modules:Litigation")) .ValidateDataAnnotations();
// 2. Register module-specific services services.AddScoped<ILegalCaseNumberGenerator, LegalCaseNumberGenerator>(); }
/// <summary> /// Middleware pipeline phase: execute after the host application pipeline is configured. /// </summary> public void UseModule(IApplicationBuilder app) { // Mount custom middleware, health checks, or webhook routing }}2. Topological Sort & Dependency Resolution
At host startup, BitzOrcas.Modularity models all declared modules as a Directed Acyclic Graph (DAG) and executes a topological sort:
Invariant Rules & Guarantees
- Foundational Modules First:
IdentityModuleis guaranteed to finish itsConfigureServicesexecution before downstream consumers execute; - Circular Dependency Detection: If Module A depends on B while B depends on A, the engine throws an immediate
InvalidModuleDependencyExceptionat build/startup, preventing corrupted states; - Scoped Configuration Access: Modules access their configuration strictly under
configuration.GetSection("Modules:<ModuleName>"), preserving clean setting boundaries.
3. Clean Host Entrypoint (Program.cs)
With the modularity engine, src/Hosts/BitzOrcas.Api remains concise and maintainable:
using BitzOrcas.Modularity;
var builder = WebApplication.CreateBuilder(args);
// 1. Discover, sort, and register all modulesbuilder.Services.AddModularMonolith(builder.Configuration);
var app = builder.Build();
// 2. Mount module middlewares in topological orderapp.UseModularMonolith();
app.Run();4. Related Architecture Decisions & Deep Dives
- Golden Sample: Sandbox Golden Sample Architecture
- Metapackage Profiles: Profiles and Metapackage Tailoring Architecture
- ADR Reference: ADR 0203: Framework & Modules Physical Directory Structure