Dependency Injection
Tayra integrates with the standard Microsoft.Extensions.DependencyInjection container. The AddTayra() extension method registers all required services, including a built-in in-memory key store, and returns a TayraBuilder for further configuration. Entity configuration is done inside the AddTayra() options lambda. For production, register a persistent key store (PostgreSQL, Vault, etc.) which overrides the default in-memory store.
What AddTayra() Registers
A single call to AddTayra() registers the following services:
| Service | Purpose |
|---|---|
ITayra | Primary user-facing API — encryption, decryption, crypto-shredding, key rotation, blind index queries |
IKeyStore | Key persistence (default: InMemoryKeyStore for development) |
ITayra is the single entry point for all data protection operations. Resolve it from the container or use TayraHost.Create() for non-DI scenarios.
Key stores are the intended extension point — use UsePostgreSqlKeyStore(), UseVaultKeyStore(), or other key store builders to swap the default.
Registration Example
var fullServices = new ServiceCollection();
fullServices.AddTayra(opts =>
{
opts.LicenseKey = licenseKey;
// How long encryption keys are cached in memory (default: 5 minutes)
opts.KeyCacheDuration = TimeSpan.FromMinutes(10);
// AES key size — 128, 192, or 256 bits (default: 256)
opts.KeySizeInBits = 256;
});Service Lifetimes
Every Tayra service is registered as a Singleton:
PersonalDataMetadataCacheuses aConcurrentDictionaryto cache type metadata. It is thread-safe and never changes once built.DefaultCryptoEnginewraps aMemoryCachefor encryption keys. The cache respects theKeyCacheDurationoption.DefaultFieldEncrypteris stateless apart from its injected dependencies.
Singleton Key Store Requirement
Your IKeyStore implementation must also be thread-safe. All built-in key stores (InMemory, PostgreSql, Vault, AzureKeyVault, AwsKms) are registered as singletons and are thread-safe.
Chaining with Key Stores
AddTayra() defaults to the built-in InMemoryKeyStore, which is suitable for development and testing. For production, chain a key store registration from the returned TayraBuilder:
services.AddTayra(opts => opts.LicenseKey = licenseKey);
// Uses InMemoryKeyStore by default (keys lost on restart)
// Local development — persistent keys across restarts
services.AddTayra(opts => opts.LicenseKey = licenseKey)
.UsePostgreSqlKeyStore(connectionString);
// Production — use a secrets manager
services.AddTayra(opts => opts.LicenseKey = licenseKey)
.UseVaultKeyStore(options => { ... });Fluent Entity Configuration
Call Entity<T>() inside the AddTayra() options lambda to configure entity types as an alternative to attributes. You can define data subject IDs, personal data fields, and replacement values entirely in code:
services.AddTayra(opts =>
{
opts.LicenseKey = "...";
opts.Entity<Customer>(e =>
{
e.DataSubjectId(c => c.Id).WithPrefix("cust-");
e.PersonalData(c => c.Name);
e.PersonalData(c => c.Email).WithMaskValue("[removed]");
});
});Blind index services are registered automatically by AddTayra() when [BlindIndex] attributes or fluent .BlindIndex() configurations are present.
TIP
See Fluent API for the complete builder reference.
Non-DI Usage
If your application doesn't use dependency injection, TayraHost.Create provides the same configuration experience. The simple form uses the in-memory key store:
// Simple — in-memory key store, no builder needed
using var simpleTayra = TayraHost.Create(opts =>
{
opts.LicenseKey = licenseKey;
});
await simpleTayra.EncryptAsync(new FluentCustomer { CustomerId = "non-di-001", Name = "Test", Email = "test@example.com" });For key stores, compliance, or other configuration, use the builder overload — it supports the same extension methods as the DI path:
// With builder — same extension methods as the DI path
using var builderTayra = TayraHost.Create(
opts => opts.LicenseKey = licenseKey,
builder =>
{
builder.UseSqliteKeyStore();
builder.AddCompliance(complianceOpts =>
{
complianceOpts.AddEntityType<FluentCustomer>();
});
});
await builderTayra.EncryptAsync(new FluentCustomer { CustomerId = "non-di-002", Name = "Builder Test", Email = "builder@example.com" });The builder overload internally creates a service collection, applies the same AddTayra() + extension method chain, and resolves ITayra. You get the same wiring — just without exposing the DI container.
See Also
- Fluent API -- Complete builder reference for entity configuration
- Options -- Configure cache duration, key size, and other settings
- Licensing -- Production license key setup
- Getting Started -- End-to-end tutorial
