Skip to content

Generated Code

The EmailModule declaration generates effect methods and DI registration. No runtime code generation — the generated layer wraps the hand-written IEmailService interface.

What Gets Generated

Given this declaration:

[EffectsModule(typeof(IEmailService))]
[ServiceRegistration(nameof(AddDefaultEmail))]
public static partial class EmailModule
{
    public static void AddDefaultEmail(this IServiceCollection services)
    {
        services.TryAddSingleton<IEmailService, InMemoryEmailService>();
    }
}

The EffectsGenerator produces:

Effect Methods

// Generated: EmailModule.Email.SendAsync<RT>(message)
public static partial class EmailModule
{
    public static partial class Email
    {
        public static Eff<RT, EmailResult> SendAsync<RT>(
            EmailMessage message)
            where RT : IHasEmailService =>
            liftEff<RT, EmailResult>(async rt =>
                await rt.EmailService.SendAsync(message));

        public static Eff<RT, IReadOnlyList<EmailResult>> SendBatchAsync<RT>(
            IReadOnlyList<EmailMessage> messages)
            where RT : IHasEmailService =>
            liftEff<RT, IReadOnlyList<EmailResult>>(async rt =>
                await rt.EmailService.SendBatchAsync(messages));
    }
}

Capability Interface

// Generated: capability for runtime constraint
public interface IHasEmailService
{
    IEmailService EmailService { get; }
}

DI Registration

The [ServiceRegistration] attribute causes the runtime bootstrapper to call AddDefaultEmail() during Add{Runtime}(). Because it uses TryAddSingleton, production providers registered first (e.g., SES) take priority over InMemoryEmailService.

Using Without Effects

You can inject IEmailService directly without the effects layer:

public class OrderService(IEmailService emailService)
{
    public async Task SendConfirmation(Order order)
    {
        await emailService.SendAsync(new EmailMessage
        {
            From = new EmailAddress("orders@example.com"),
            To = [new EmailAddress(order.CustomerEmail)],
            Subject = $"Order #{order.Id} Confirmed",
            HtmlBody = RenderTemplate(order)
        });
    }
}

For functional effect composition, see Effects Composition.