Skip to main content
Version: v1.7.0

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.