Skip to content

API Reference

Complete reference for SimpleModule's public interfaces, attributes, types, and generated extension methods.

Interfaces

IModule

The core module interface. All modules must implement this interface (typically via a class decorated with [Module]). All methods have default (empty) implementations -- override only what you need.

csharp
namespace SimpleModule.Core;

public interface IModule
{
    virtual void ConfigureServices(IServiceCollection services, IConfiguration configuration) { }
    virtual void ConfigureEndpoints(IEndpointRouteBuilder endpoints) { }
    virtual void ConfigureMiddleware(IApplicationBuilder app) { }
    virtual void ConfigureMenu(IMenuBuilder menus) { }
    virtual void ConfigurePermissions(PermissionRegistryBuilder builder) { }
    virtual void ConfigureSettings(ISettingsBuilder settings) { }
}
MethodCalled WhenPurpose
ConfigureServicesApplication startupRegister DI services and configuration
ConfigureEndpointsApplication startupManual endpoint registration (escape hatch)
ConfigureMiddlewareApplication startupRegister ASP.NET middleware
ConfigureMenuApplication startupAdd navigation menu items
ConfigurePermissionsApplication startupRegister permission definitions
ConfigureSettingsApplication startupRegister settings definitions

INFO

ConfigureEndpoints is an escape hatch. If your module has IEndpoint/IViewEndpoint implementations, the source generator registers them automatically. Only override ConfigureEndpoints for non-standard routing needs.


IEndpoint

Defines an API endpoint. Implementations are auto-discovered by the source generator and mapped to route groups based on the module's RoutePrefix.

csharp
namespace SimpleModule.Core;

public interface IEndpoint
{
    void Map(IEndpointRouteBuilder app);
}

Usage:

csharp
public sealed class GetProducts : IEndpoint
{
    public void Map(IEndpointRouteBuilder app)
    {
        app.MapGet("/", async (IProductContracts products) =>
        {
            var result = await products.GetAllAsync();
            return TypedResults.Ok(result);
        });
    }
}

IViewEndpoint

Defines a view (page) endpoint that renders an Inertia.js page. Implementations are auto-discovered and mapped to route groups based on the module's ViewPrefix.

csharp
namespace SimpleModule.Core;

public interface IViewEndpoint
{
    void Map(IEndpointRouteBuilder app);
}

Usage:

csharp
public sealed class Browse : IViewEndpoint
{
    public void Map(IEndpointRouteBuilder app)
    {
        app.MapGet("/", async (IProductContracts products, HttpContext context) =>
        {
            var result = await products.GetAllAsync();
            return Inertia.Render("Products/Browse", new { products = result });
        });
    }
}

WARNING

Every IViewEndpoint must have a corresponding entry in the module's Pages/index.ts. See the Pages Registry Pattern for details.


IEvent

Marker interface for event types. All events published through the event bus must implement this interface.

csharp
namespace SimpleModule.Core.Events;

public interface IEvent;

Usage:

csharp
public sealed record OrderCreatedEvent(int OrderId, string CustomerName) : IEvent;

IEventBus

Publishes events to all registered handlers with exception isolation semantics.

csharp
namespace SimpleModule.Core.Events;

public interface IEventBus
{
    Task PublishAsync<T>(T @event, CancellationToken cancellationToken = default)
        where T : IEvent;
}

Behavior:

  • Handlers execute sequentially in registration order
  • Handler failures are isolated -- if one handler throws, the others still run
  • After all handlers execute, any exceptions are rethrown as AggregateException

Usage:

csharp
public sealed class CreateOrder : IEndpoint
{
    public void Map(IEndpointRouteBuilder app)
    {
        app.MapPost("/", async (CreateOrderRequest request,
            IOrderContracts orders, IEventBus eventBus) =>
        {
            var order = await orders.CreateAsync(request);
            await eventBus.PublishAsync(new OrderCreatedEvent(order.Id, request.CustomerName));
            return TypedResults.Created($"/{order.Id}", order);
        });
    }
}

IEventHandler<T>

Handles a specific event type. Implementations are registered in DI and invoked by the event bus.

csharp
namespace SimpleModule.Core.Events;

public interface IEventHandler<in T> where T : IEvent
{
    Task HandleAsync(T @event, CancellationToken cancellationToken);
}

Usage:

csharp
public sealed class OrderCreatedAuditHandler : IEventHandler<OrderCreatedEvent>
{
    public async Task HandleAsync(OrderCreatedEvent @event, CancellationToken cancellationToken)
    {
        // Log the order creation for audit purposes
    }
}

IMenuBuilder

Fluent interface for adding navigation menu items during module initialization.

csharp
namespace SimpleModule.Core.Menu;

public interface IMenuBuilder
{
    IMenuBuilder Add(MenuItem item);
}

IMenuRegistry

Read-only access to registered menu items at runtime, grouped by section.

csharp
namespace SimpleModule.Core.Menu;

public interface IMenuRegistry
{
    IReadOnlyList<MenuItem> GetItems(MenuSection section);
}

ISettingsBuilder

Interface for registering module settings definitions during module initialization.

csharp
namespace SimpleModule.Core.Settings;

public interface ISettingsBuilder
{
    ISettingsBuilder Add(SettingDefinition definition);
}

IModulePermissions

Marker interface for permission classes. Implementations are auto-discovered by the source generator. Permission classes must be sealed and contain only public const string fields.

csharp
namespace SimpleModule.Core.Authorization;

public interface IModulePermissions;

Usage:

csharp
public sealed class ProductPermissions : IModulePermissions
{
    public const string View = "Products.View";
    public const string Create = "Products.Create";
    public const string Edit = "Products.Edit";
    public const string Delete = "Products.Delete";
}

Attributes

[Module]

Marks a class as a module. Required for source generator discovery.

csharp
namespace SimpleModule.Core;

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public sealed class ModuleAttribute : Attribute
{
    public string Name { get; }
    public string Version { get; }
    public string RoutePrefix { get; set; } = "";
    public string ViewPrefix { get; set; } = "";

    public ModuleAttribute(string name, string version = "1.0.0") { ... }
}
PropertyDescriptionDefault
NameModule display name (required)--
VersionModule version"1.0.0"
RoutePrefixURL prefix for API endpoints""
ViewPrefixURL prefix for view endpoints""

Usage:

csharp
[Module("Products", RoutePrefix = "/api/products", ViewPrefix = "/products")]
public sealed class ProductsModule : IModule
{
    public void ConfigureServices(IServiceCollection services, IConfiguration configuration)
    {
        // Register module services
    }
}

[Dto]

Marks a type for TypeScript generation. Not required for types in *.Contracts assemblies (those are included by convention).

csharp
[AttributeUsage(
    AttributeTargets.Class | AttributeTargets.Struct,
    AllowMultiple = false, Inherited = false
)]
public sealed class DtoAttribute : Attribute { }

[NoDtoGeneration]

Excludes a public type in a Contracts assembly from automatic DTO/TypeScript generation.

csharp
[AttributeUsage(
    AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface,
    AllowMultiple = false, Inherited = false
)]
public sealed class NoDtoGenerationAttribute : Attribute { }

[RequirePermission]

Declares that an endpoint requires specific permissions. Used by the source generator to apply authorization metadata.

csharp
namespace SimpleModule.Core.Authorization;

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public sealed class RequirePermissionAttribute : Attribute
{
    public string[] Permissions { get; }

    public RequirePermissionAttribute(params string[] permissions) { ... }
}

Usage:

csharp
[RequirePermission(ProductPermissions.Create)]
public sealed class CreateProduct : IEndpoint
{
    public void Map(IEndpointRouteBuilder app)
    {
        app.MapPost("/", async (CreateProductRequest request, IProductContracts products) =>
        {
            var product = await products.CreateAsync(request);
            return TypedResults.Created($"/{product.Id}", product);
        });
    }
}

Types

PagedResult<T>

Standard wrapper for paginated query results.

csharp
namespace SimpleModule.Core;

public class PagedResult<T>
{
    public IReadOnlyList<T> Items { get; set; } = [];
    public int TotalCount { get; set; }
    public int Page { get; set; }
    public int PageSize { get; set; }
}

Represents a navigation menu entry.

csharp
namespace SimpleModule.Core.Menu;

public sealed class MenuItem
{
    public required string Label { get; init; }
    public required string Url { get; init; }
    public string Icon { get; init; } = "";
    public int Order { get; init; }
    public MenuSection Section { get; init; } = MenuSection.Navbar;
    public bool RequiresAuth { get; init; } = true;
    public string? Group { get; init; }
}

Enum defining where a menu item appears in the UI.

csharp
namespace SimpleModule.Core.Menu;

public enum MenuSection
{
    Navbar,
    UserDropdown,
    AdminSidebar,
    AppSidebar,
}

ModuleDbContextInfo

Associates a module name with its DbContext type for schema isolation.

csharp
namespace SimpleModule.Database;

public sealed record ModuleDbContextInfo(string ModuleName, Type DbContextType);

PermissionRegistry

Read-only registry of all permissions in the application. Registered as a singleton.

csharp
namespace SimpleModule.Core.Authorization;

public sealed class PermissionRegistry
{
    public IReadOnlySet<string> AllPermissions { get; }
    public IReadOnlyDictionary<string, IReadOnlyList<string>> ByModule { get; }
}

PermissionRegistryBuilder

Builder for constructing the PermissionRegistry during startup. Passed to IModule.ConfigurePermissions.

csharp
namespace SimpleModule.Core.Authorization;

public sealed class PermissionRegistryBuilder
{
    public void AddPermissions<T>() where T : class { ... }
    public void AddPermission(string permission) { ... }
    public PermissionRegistry Build() { ... }
}

Permissions follow the convention ModuleName.Action (e.g., Products.Create). The module prefix is extracted from the first segment before the ..


SettingDefinition

Defines a configurable setting for a module.

csharp
namespace SimpleModule.Core.Settings;

public class SettingDefinition
{
    public string Key { get; set; } = string.Empty;
    public string DisplayName { get; set; } = string.Empty;
    public string? Description { get; set; }
    public string? Group { get; set; }
    public SettingScope Scope { get; set; }
    public string? DefaultValue { get; set; }
    public SettingType Type { get; set; }
}

Generated Extension Methods

These extension methods are generated by the source generator and called in Program.cs:

AddModules

csharp
public static IServiceCollection AddModules(
    this IServiceCollection services,
    IConfiguration configuration)

Registers all discovered modules' services in dependency order. This includes:

  • Calling ConfigureServices on each module (topologically sorted)
  • Registering auto-discovered contract implementations as scoped services
  • Building and registering the PermissionRegistry
  • Configuring JSON serializer options with the generated type info resolver

MapModuleEndpoints

csharp
public static WebApplication MapModuleEndpoints(this WebApplication app)

Maps all discovered IEndpoint and IViewEndpoint implementations. API endpoints are grouped by RoutePrefix with authorization required. View endpoints are grouped by ViewPrefix and excluded from API descriptions.

Modules that override ConfigureEndpoints are called separately (the escape hatch).

CollectModuleMenuItems

csharp
public static IServiceCollection CollectModuleMenuItems(
    this IServiceCollection services)

Invokes ConfigureMenu on all modules that implement it and registers the resulting IMenuRegistry as a singleton.

Next Steps

Released under the MIT License.