--- title: "Dependency Injection" description: "Integrate RoomSharp with ASP.NET Core dependency injection." canonical: "https://roomsharp.dev/docs/v0.4.7/dependency-injection" source: "src/content/v0.4.7/dependency-injection.mdx" --- # Dependency Injection RoomSharp ships with a companion package, **RoomSharp.DependencyInjection**, that wires databases and DAOs into `IServiceCollection` using familiar ASP.NET Core patterns. ## Installation ```bash dotnet add package RoomSharp.DependencyInjection ``` ## Basic Registration Register your database during startup: ```csharp builder.Services.AddRoomSharpDatabase(context => { var configuration = context.Services.GetRequiredService(); var connString = configuration.GetConnectionString("Default")!; context.UseSqlite(connString); context.Builder .SetVersion(2) .AddMigrations(new InitialMigration()) .SetEntities(typeof(User), typeof(Todo)); }); builder.Services.AddRoomSharpDao(db => db.TodoDao); ``` ## Provider Shortcuts Use convenience methods instead of manually creating provider instances: ```csharp // SQLite context.UseSqlite("app.db"); // SQL Server (requires RoomSharp.SqlServer) context.UseSqlServer("Server=.;Database=MyApp;Trusted_Connection=True;"); // PostgreSQL (requires RoomSharp.PostgreSql) context.UsePostgres("Host=localhost;Database=myapp;Username=user;Password=pass;"); // MySQL/MariaDB (requires RoomSharp.MySql) context.UseMySql("Server=localhost;Database=myapp;User=root;Password=pass;"); ``` ## Service Lifetime Control the database lifetime with the `ServiceLifetime` parameter: ```csharp // Singleton (default) - single instance shared across the app builder.Services.AddRoomSharpDatabase(ctx => ctx.UseSqlite("app.db")); // Scoped - new instance per request/scope builder.Services.AddRoomSharpDatabase( ctx => ctx.UseSqlite("app.db"), ServiceLifetime.Scoped); // Shorthand for scoped registration builder.Services.AddRoomSharpScopedDatabase(ctx => ctx.UseSqlite("app.db")); ``` ## Database Factory Pattern For background services, Blazor Server, or manual lifecycle control, use the factory pattern: ```csharp // Register the factory builder.Services.AddRoomSharpDatabaseFactory(ctx => { ctx.UseSqlServer(configuration.GetConnectionString("Default")!); }); // Inject and use in a background service public class MyBackgroundService : BackgroundService { private readonly IRoomDatabaseFactory _dbFactory; public MyBackgroundService(IRoomDatabaseFactory dbFactory) { _dbFactory = dbFactory; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { // Create a new database instance when needed using var db = _dbFactory.Create(); await db.TodoDao.GetAllAsync(); // db is disposed when leaving the scope } } ``` ## Configuration-Based Registration Bind connection strings directly from `IConfiguration`: ```csharp builder.Services.AddRoomSharpDatabase( configuration, connectionStringName: "Default", providerFactory: sp => new SqlServerProvider(), // Optional custom provider configure: builder => builder.SetVersion(2)); // Optional builder tweaks ``` ## DAO Registration DAOs default to scoped lifetime but can be customized: ```csharp // Scoped (default) - new DAO instance per scope builder.Services.AddRoomSharpDao(db => db.TodoDao); // Singleton - shared DAO instance builder.Services.AddRoomSharpDao( db => db.TodoDao, ServiceLifetime.Singleton); ``` ## API Reference ### Database Registration Methods | Method | Description | |--------|-------------| | `AddRoomSharpDatabase(configure, lifetime?)` | Register database with builder callback | | `AddRoomSharpDatabase(context, lifetime?)` | Register with access to IServiceProvider | | `AddRoomSharpDatabase(config, connName, ...)` | Bind from IConfiguration | | `AddRoomSharpScopedDatabase(configure)` | Shorthand for scoped registration | | `AddRoomSharpDatabaseFactory(configure)` | Register factory for manual lifecycle | | `AddRoomSharpDao(factory, lifetime?)` | Register DAO with factory | ### Context Methods | Method | Description | |--------|-------------| | `UseSqlite(path, mode?, cache?)` | Configure SQLite with file path and optional mode/cache | | `UseSqliteInMemory()` | Configure in-memory SQLite database | | `UseSqliteWithConnectionString(connStr)` | Configure SQLite with full connection string | | `UseSqliteWithConnectionString(builder)` | Configure SQLite with SqliteConnectionStringBuilder | | `UseSqlServer(connStr)` | Configure SQL Server | | `UsePostgres(connStr)` | Configure PostgreSQL | | `UseMySql(connStr)` | Configure MySQL/MariaDB | | `UseProvider(connStr)` | Use custom provider type from DI | | `UseProvider(provider, connStr)` | Use externally constructed provider | ## Example: Complete Setup ```csharp var builder = WebApplication.CreateBuilder(args); // Register database builder.Services.AddRoomSharpDatabase(context => { var connString = builder.Configuration.GetConnectionString("Default")!; context.UseSqlite(connString); context.Builder .SetVersion(1) .SetJournalMode(JournalMode.WAL) .EnableMultiInstanceInvalidation(); }); // Register DAOs builder.Services.AddRoomSharpDao(db => db.UserDao); builder.Services.AddRoomSharpDao(db => db.TodoDao); var app = builder.Build(); // Use in controllers/services app.MapGet("/users", async (IUserDao userDao) => { return await userDao.GetAllAsync(); }); app.Run(); ``` ## Health Checks Integrate RoomSharp databases with ASP.NET Core health checks: ```csharp // In Program.cs builder.Services.AddHealthChecks() .AddRoomSharpDatabase(); // Map health endpoint app.MapHealthChecks("/health"); ``` The health check verifies that the database instance can be resolved from DI successfully. ## Lifetime Validation (v0.4.4+) RoomSharp validates lifetime compatibility to prevent **captive dependencies**: ```csharp // ✅ Valid: Singleton database with Scoped DAO builder.Services.AddRoomSharpDatabase(ctx => ctx.UseSqlite("app.db")); builder.Services.AddRoomSharpDao(db => db.TodoDao); // ❌ Invalid: Scoped database with Singleton DAO (throws at startup) builder.Services.AddRoomSharpDatabase( ctx => ctx.UseSqlite("app.db"), ServiceLifetime.Scoped); builder.Services.AddRoomSharpDao( db => db.TodoDao, ServiceLifetime.Singleton); // Throws InvalidOperationException! ``` A captive dependency occurs when a longer-lived service captures a shorter-lived dependency. The Singleton DAO would hold a stale reference to the Scoped database. ## Async Factory (v0.4.4+) Use `CreateAsync` for async initialization scenarios: ```csharp public class MyBackgroundService : BackgroundService { private readonly IRoomDatabaseFactory _dbFactory; protected override async Task ExecuteAsync(CancellationToken stoppingToken) { // Async creation - useful for future extensibility await using var db = await _dbFactory.CreateAsync(stoppingToken); await db.TodoDao.GetAllAsync(); } } ``` For most web applications, use Singleton lifetime for the database and Scoped for DAOs. This balances connection reuse with request isolation.