Skip to main content

Registration

This page covers how to register custom repositories with the DI container using the Kista fluent builder API.

Basic Registration

Use AddRepository<T>() on the repository context builder. The driver's open-generic registrations (e.g. InMemoryRepository<> from .UseInMemory()) serve as defaults for all entities; AddRepository<T>() registers a concrete type that overrides the open generic for that specific entity:

builder.Services.AddRepositoryContext()
.UseInMemory() // default: InMemoryRepository for all entities
.AddRepository<SpecialProductRepo>(); // override: SpecialProductRepo for Product only
builder.Services.AddRepositoryContext()
.UseEntityFramework<AppDbContext>(b => b
.ConfigureDbContext(opts => opts.UseSqlServer("...")))
.AddRepository<ProductRepository>();

What Gets Registered

The AddRepository<T>() method scans the specified type and registers all relevant services:

builder.Services.AddRepositoryContext()
.UseInMemory()
.AddRepository<ProductRepository>();

This registers:

Service TypeDescription
ProductRepositoryThe concrete implementation
IProductRepositoryYour custom interface
IRepository<Product, Guid>The base repository contract

All registrations are scoped by default, matching the typical request lifetime for data access.

Lifetime Configuration

Override the default lifetime:

builder.Services.AddRepositoryContext()
.UseInMemory()
.AddRepository<ProductRepository>(ServiceLifetime.Singleton);

Available lifetimes:

LifetimeUse Case
Scoped (default)Request-scoped data access, typical web apps
TransientStateless repositories, no shared state
SingletonRead-only repositories, cached data

Open Generic Repositories

Open generic repositories are registered as open generics:

public class NamedEntityRepository<TEntity> : Repository<TEntity, Guid>, INamedEntityRepository<TEntity>
where TEntity : class, INamedEntity {
// ...
}

builder.Services.AddRepositoryContext()
.UseEntityFramework<AppDbContext>()
.AddRepository(typeof(NamedEntityRepository<>));

This allows resolution of INamedEntityRepository<Product>, INamedEntityRepository<Category>, etc.

Multiple Repositories

Register multiple repositories in sequence:

builder.Services.AddRepositoryContext()
.UseEntityFramework<AppDbContext>()
.AddRepository<ProductRepository>()
.AddRepository<OrderRepository>()
.AddRepository<CustomerRepository>();

Or chain them:

var context = builder.Services.AddRepositoryContext()
.UseEntityFramework<AppDbContext>();

context.AddRepository<ProductRepository>();
context.AddRepository<OrderRepository>();
context.AddRepository<CustomerRepository>();

Assembly Scanning

Use ScanRepositories() to automatically discover and register repository types from one or more assemblies:

builder.Services.AddRepositoryContext()
.UseEntityFramework<AppDbContext>()
.ScanRepositories(typeof(ProductRepository).Assembly);

This scans the assembly for all types that implement IRepository<TEntity> and registers them automatically.

Consuming the Repository

After registration, resolve the repository through DI:

public class ProductService {
private readonly IProductRepository _products;

public ProductService(IProductRepository products) {
_products = products;
}

public async Task<Product?> GetByCodeAsync(string code, CancellationToken ct = default) {
return await _products.FindByCodeAsync(code, ct);
}
}

You can also resolve the base interface:

public class GenericService {
private readonly IRepository<Product, Guid> _products;

public GenericService(IRepository<Product, Guid> products) {
_products = products;
}

public async Task<Product?> GetByIdAsync(Guid id, CancellationToken ct = default) {
return await _products.FindAsync(id, ct);
}
}

Deprecated Interface Registration

The legacy extension interfaces (IQueryableRepository, IPageableRepository, IFilterableRepository) are not registered automatically for new repositories. If your custom repository implements these deprecated interfaces (for backward compatibility), they will still be registered:

// Legacy — not recommended for new code
public class LegacyRepository : Repository<Product, Guid>,
IQueryableRepository<Product, Guid> {
// ...
}

// This would register IQueryableRepository<Product, Guid> as well
builder.Services.AddRepositoryContext()
.UseInMemory()
.AddRepository<LegacyRepository>();

New code should not rely on these interfaces. Use domain-specific methods on your custom interface instead.