Skip to content

Attribute Reference

All attributes and marker interfaces used by the Dispatch module.

[DispatchModule]

Marks a static partial class as the dispatch entry point. The generator discovers all [CommandHandler] and [QueryHandler] methods in the assembly and generates typed dispatch overloads.

Property Type Default Description
AutoCommit bool true Call CommitAsync() on all IAutoCommittable capabilities after command dispatch
[DispatchModule]
public static partial class AppDispatch;

// Disable auto-commit for manual transaction control
[DispatchModule(AutoCommit = false)]
public static partial class AppDispatch;

[CommandHandler]

Marks a static method as a command handler. The method must be static, return Eff<TRuntime, T>, and have the command type as its first parameter.

Property Type Default Description
Audited bool false Record an audit entry after handler execution
Validated bool false Auto-generate an applicative validator from DataAnnotations on the input type. Mutually exclusive with ValidatorType (DSDSP10)
ValidatorType Type? null Type containing a static Validate method called before the handler. Mutually exclusive with Validated (DSDSP10)
public static class OrderCommands
{
    [CommandHandler]
    public static Eff<AppRuntime, OrderCreated> Handle(CreateOrder cmd) => ...

    [CommandHandler(Audited = true, ValidatorType = typeof(CreateOrderValidator))]
    public static Eff<AppRuntime, OrderUpdated> Handle(UpdateOrder cmd) => ...
}

[QueryHandler]

Marks a static method as a query handler. Same signature requirements as [CommandHandler] — static, returns Eff<TRuntime, T>, first parameter is the query type.

Property Type Default Description
Audited bool false Record an audit entry after handler execution
Validated bool false Auto-generate an applicative validator from DataAnnotations on the input type. Mutually exclusive with ValidatorType (DSDSP10)
ValidatorType Type? null Type containing a static Validate method called before the handler. Mutually exclusive with Validated (DSDSP10)
public static class OrderQueries
{
    [QueryHandler]
    public static Eff<AppRuntime, QueryResult<OrderDto>> Handle(GetOrders query) => ...
}

Queries skip auto-commit

The auto-commit step is only generated for command handlers. Query handlers never trigger IAutoCommittable.CommitAsync().

[Authorize]

Specifies an authorization policy required to execute the handler. Can be applied multiple times — all policies must pass. In the web layer, the policy name is forwarded to ASP.NET's RequireAuthorization.

Property Type Description
Policy string The policy name (constructor parameter)
[CommandHandler]
[Authorize("CanCreateOrders")]
[Authorize("IsAdmin")]
public static Eff<AppRuntime, OrderCreated> Handle(CreateOrder cmd) => ...

Use nameof to reference policies for compile-time safety:

[CommandHandler]
[Authorize(nameof(Policies.CanCreateOrders))]
public static Eff<AppRuntime, OrderCreated> Handle(CreateOrder cmd) => ...

[AuthPolicies] and [AuthPolicy]

Define authorization policies in a class decorated with [AuthPolicies]. Each [AuthPolicy] method becomes a named policy — the method name is the policy name.

using System.Security.Claims;
using Deepstaging.Dispatch;

[AuthPolicies]
public static partial class Policies
{
    [AuthPolicy]
    public static bool CanCreateOrders(ClaimsPrincipal user) =>
        user.HasClaim("role", "editor");

    [AuthPolicy]
    public static bool IsAdmin(ClaimsPrincipal user) =>
        user.IsInRole("admin");
}

The generator creates a Register(AuthorizationOptions) method that wires all policies into ASP.NET:

// In Program.cs / startup
builder.Services.AddAuthorization(Policies.Register);

See the Authorization Policies page for the full reference — testing, non-web usage, registration patterns, and complete examples.

[Idempotent]

Marks a handler as requiring an idempotency key. When applied, the generated web endpoint enforces unique processing per key — duplicate requests with the same idempotency key return the cached result instead of re-executing the handler.

[CommandHandler]
[Idempotent]
[HttpPost("/orders")]
public static Eff<AppRuntime, OrderCreated> Handle(CreateOrder cmd) => ...

The idempotency middleware stores results keyed by the Idempotency-Key request header.

[RateLimit]

Overrides the default rate limit policy for a specific handler. The generated endpoint calls .RequireRateLimiting("PolicyName").

Property Type Description
Policy string The rate limit policy name (constructor parameter)
[CommandHandler]
[RateLimit("ds_per_tenant")]
[HttpPost("/orders")]
public static Eff<AppRuntime, OrderCreated> Handle(CreateOrder cmd) => ...

Rate limit policies are configured in ASP.NET middleware (AddRateLimiter) — the attribute simply wires the handler to a named policy.

Marker Interfaces

ICommand

Marker interface for command types — records that represent intent to change state.

public record CreateOrder(string Name, int Quantity) : ICommand;
public record PublishArticle(ArticleId ArticleId) : ICommand;

IQuery

Marker interface for query types — records that represent intent to read state.

public record GetOrders(int Page = 1, int PageSize = 20) : IQuery;
public record GetOrderById(OrderId Id) : IQuery;

IAutoCommittable

Implemented by capabilities that need transactional commit after command dispatch. When AutoCommit = true (default), the generated pipeline calls CommitAsync() on the runtime if it implements this interface.

public interface IAutoCommittable
{
    Task CommitAsync(CancellationToken cancellationToken = default);
}

Common implementation — EF Core DbContext:

public class AppDbContext : DbContext, IAutoCommittable
{
    public Task CommitAsync(CancellationToken cancellationToken) =>
        SaveChangesAsync(cancellationToken);
}