Skip to content

AddLensServices

Verified by tests

ServiceRegistrationGeneratorTests — library CI run #31657041675 (2026-08-13)

AddLensServices is a source-generated extension method that registers all discovered Lens implementations with the dependency injection container.

Updated

AddWhizbang() invokes this method automatically via ServiceRegistrationCallbacks — an explicit call is only needed when registering services without AddWhizbang(), or with different options.

Signature

Signature

public static IServiceCollection AddLensServices(
    this IServiceCollection services,
    Action<ServiceRegistrationOptions>? configure = null)

Parameters

Parameter Type Description
services IServiceCollection The service collection to add registrations to
configure Action<ServiceRegistrationOptions>? Optional configuration action

Returns

IServiceCollection - The service collection for method chaining.

Basic Usage

Register Lens Services

var builder = WebApplication.CreateBuilder(args);

// Register all discovered Lens implementations
builder.Services.AddLensServices();

With Options

Register with Options

// Disable self-registration
builder.Services.AddLensServices(options =>
    options.IncludeSelfRegistration = false);

What Gets Registered

The source generator discovers classes that: - Implement a user-defined interface extending ILensQuery (registered against the user interface), or implement ILensQuery<TModel> directly with a closed generic argument (registered against the Whizbang interface) - Are not abstract

For each discovered Lens, it generates:

Generated Registration

// Interface registration
services.AddTransient<IOrderLens, OrderLens>();

// Self-registration (when IncludeSelfRegistration = true)
services.AddTransient<OrderLens>();

Registration Lifetime

All Lenses are registered as Transient services: - Fresh instance per resolution - Scoped dependencies (like DbContext) come from the resolving scope - No accidental state sharing between resolutions

Example Lens

Example Lens Implementation

public interface IOrderLens : ILensQuery {
  Task<OrderSummary?> GetByIdAsync(OrderId orderId, CancellationToken ct);
  Task<IReadOnlyList<OrderSummary>> GetByCustomerAsync(CustomerId customerId, CancellationToken ct);
  Task<IReadOnlyList<OrderSummary>> GetRecentAsync(int count, CancellationToken ct);
}

public class OrderLens : IOrderLens {
  private readonly AppDbContext _db;

  public OrderLens(AppDbContext db) {
    _db = db;
  }

  public Task<OrderSummary?> GetByIdAsync(OrderId orderId, CancellationToken ct) =>
    _db.OrderSummaries.FirstOrDefaultAsync(o => o.Id == orderId, ct);

  public async Task<IReadOnlyList<OrderSummary>> GetByCustomerAsync(
      CustomerId customerId,
      CancellationToken ct) =>
    await _db.OrderSummaries
       .Where(o => o.CustomerId == customerId)
       .OrderByDescending(o => o.CreatedAt)
       .ToListAsync(ct);

  public async Task<IReadOnlyList<OrderSummary>> GetRecentAsync(int count, CancellationToken ct) =>
    await _db.OrderSummaries
       .OrderByDescending(o => o.CreatedAt)
       .Take(count)
       .ToListAsync(ct);
}

The generator automatically discovers OrderLens and generates registration code.

Using Lenses

After registration, inject Lenses into controllers, services, or GraphQL resolvers:

Using an Injected Lens

[ApiController]
[Route("api/orders")]
public class OrdersController : ControllerBase {
  private readonly IOrderLens _orderLens;

  public OrdersController(IOrderLens orderLens) {
    _orderLens = orderLens;
  }

  [HttpGet("{id}")]
  public async Task<ActionResult<OrderSummary>> GetOrder(
      [FromRoute] OrderId id,
      CancellationToken ct) {

    var order = await _orderLens.GetByIdAsync(id, ct);
    return order is null ? NotFound() : Ok(order);
  }
}

Combining with Other Registrations

Full Registration Setup

var builder = WebApplication.CreateBuilder(args);

// Database
builder.Services.AddDbContext<AppDbContext>(...);

// Core Whizbang (auto-registers discovered Perspectives and Lenses)
builder.Services.AddWhizbang();

// Explicit generated registrations — only when bypassing AddWhizbang()
builder.Services.AddPerspectiveServices();
builder.Services.AddLensServices();

// Or use the combined method:
// builder.Services.AddAllWhizbangServices();

See Also