dotnet-cqrs/docs/core-features/commands/command-registration.md

3.7 KiB

Command Registration

How to register command handlers in dependency injection.

Basic Registration

Command with Result

builder.Services.AddCommand<CreateUserCommand, int, CreateUserCommandHandler>();

This registers:

  • Handler as ICommandHandler<CreateUserCommand, int>
  • Metadata for endpoint discovery
  • Scoped lifetime (default)

Command without Result

builder.Services.AddCommand<DeleteUserCommand, DeleteUserCommandHandler>();

Registration with Validator

builder.Services.AddCommand<CreateUserCommand, int, CreateUserCommandHandler, CreateUserCommandValidator>();

This registers:

  • Handler
  • Validator as IValidator<CreateUserCommand>
  • Metadata

Registration with Workflow

builder.Services.AddCommandWithWorkflow<CreateUserCommand, int, UserWorkflow, CreateUserCommandHandler>();

For event-emitting commands.

Service Lifetimes

services.AddCommand<CreateUserCommand, int, CreateUserCommandHandler>();
// Handler is Scoped

Characteristics:

  • One instance per request
  • Can inject DbContext
  • Disposed after request

Custom Lifetime

// Transient
services.AddTransient<ICommandHandler<CreateUserCommand, int>, CreateUserCommandHandler>();

// Singleton (not recommended - can't inject DbContext)
services.AddSingleton<ICommandHandler<CreateUserCommand, int>, CreateUserCommandHandler>();

Bulk Registration

Extension Methods

// Extensions/ServiceCollectionExtensions.cs
public static class ServiceCollectionExtensions
{
    public static IServiceCollection AddUserCommands(this IServiceCollection services)
    {
        services.AddCommand<CreateUserCommand, int, CreateUserCommandHandler, CreateUserCommandValidator>();
        services.AddCommand<UpdateUserCommand, UpdateUserCommandHandler, UpdateUserCommandValidator>();
        services.AddCommand<DeleteUserCommand, DeleteUserCommandHandler>();
        return services;
    }

    public static IServiceCollection AddOrderCommands(this IServiceCollection services)
    {
        services.AddCommand<PlaceOrderCommand, int, PlaceOrderCommandHandler>();
        services.AddCommand<CancelOrderCommand, CancelOrderCommandHandler>();
        return services;
    }
}

// Usage in Program.cs
builder.Services.AddUserCommands();
builder.Services.AddOrderCommands();

Module Pattern

public interface IModule
{
    void RegisterServices(IServiceCollection services);
}

public class UserModule : IModule
{
    public void RegisterServices(IServiceCollection services)
    {
        // Commands
        services.AddCommand<CreateUserCommand, int, CreateUserCommandHandler>();
        services.AddCommand<UpdateUserCommand, UpdateUserCommandHandler>();

        // Queries
        services.AddQuery<GetUserQuery, UserDto, GetUserQueryHandler>();

        // Services
        services.AddScoped<IUserRepository, UserRepository>();
    }
}

// Auto-register all modules
var modules = typeof(Program).Assembly
    .GetTypes()
    .Where(t => typeof(IModule).IsAssignableFrom(t) && !t.IsInterface)
    .Select(Activator.CreateInstance)
    .Cast<IModule>();

foreach (var module in modules)
{
    module.RegisterServices(builder.Services);
}

Organizing Registrations

By Feature

Program.cs
Extensions/
  UserServiceRegistration.cs
  OrderServiceRegistration.cs
  ProductServiceRegistration.cs

By Layer

Program.cs
Extensions/
  CommandRegistration.cs
  QueryRegistration.cs
  RepositoryRegistration.cs

See Also