Nabs.Launchpad.Core.Persistence
10.0.219
Prefix Reserved
dotnet add package Nabs.Launchpad.Core.Persistence --version 10.0.219
NuGet\Install-Package Nabs.Launchpad.Core.Persistence -Version 10.0.219
<PackageReference Include="Nabs.Launchpad.Core.Persistence" Version="10.0.219" />
<PackageVersion Include="Nabs.Launchpad.Core.Persistence" Version="10.0.219" />
<PackageReference Include="Nabs.Launchpad.Core.Persistence" />
paket add Nabs.Launchpad.Core.Persistence --version 10.0.219
#r "nuget: Nabs.Launchpad.Core.Persistence, 10.0.219"
#:package Nabs.Launchpad.Core.Persistence@10.0.219
#addin nuget:?package=Nabs.Launchpad.Core.Persistence&version=10.0.219
#tool nuget:?package=Nabs.Launchpad.Core.Persistence&version=10.0.219
Nabs Launchpad Core Persistence Library
The Nabs Launchpad Core Persistence library provides flexible database configuration and repository patterns for Entity Framework Core applications. This library supports SQL Server (local containers and Azure), Cosmos DB, and in-memory storage with environment-aware connection string management.
Key Features
- Multi-Database Support: SQL Server, Azure SQL, Cosmos DB, and In-Memory databases
- Environment-Aware Configuration: Automatic detection of Azure vs local environments
- Azure Identity Integration: Passwordless authentication for Azure SQL databases
- Local Container Support: Easy configuration for local SQL Server containers
- DbContext Factory Pattern: Proper lifetime management for EF Core contexts
- In-Memory Repository: Simple concurrent dictionary-based repository for testing
- Fluent Configuration API: Easy-to-use extension methods for database setup
- Design-Time Support: Integration with EF Core migrations and tooling
Core Components
ProjectExtensions
Provides extension methods (AddSqlDb) for configuring SQL Server and Azure SQL databases with automatic environment detection.
ISqlConnectionStringProvider
Interface for providing connection strings with different implementations for various scenarios.
SqlConnectionStringProvider
Direct connection string provider for explicit connection string configuration.
SqlLocalContainerConnectionStringProvider
Provides connection strings for local SQL Server containers (e.g., Docker containers).
SqlAzureIdentityConnectionStringProvider
Provides connection strings for Azure SQL with Azure Identity authentication (passwordless).
SqlDbContextFactory
Factory for creating DbContext instances with proper connection string resolution.
InMemoryRepository<TId, TItem>
Abstract base class for in-memory repositories using concurrent dictionaries.
Usage Examples
Basic SQL Server Setup with Connection String
using Nabs.Launchpad.Core.Persistence;
var builder = WebApplication.CreateBuilder(args);
// Simple connection string configuration
builder.Services.AddSqlDb<MyDbContext>(
builder.Configuration.GetConnectionString("DefaultConnection")!
);
var app = builder.Build();
Local Container Configuration
// For local development with Docker SQL Server
builder.Services.AddSqlDb<MyDbContext>(
sqlContainerConfig: options =>
{
options.Server = "localhost,1433";
options.Database = "MyDatabase";
options.UserId = "sa";
options.Password = "YourStrong@Password";
options.TrustServerCertificate = true;
},
sqlAzureConfig: null // Not used locally
);
Azure SQL with Managed Identity
// Automatically uses Azure Identity when deployed to Azure
builder.Services.AddSqlDb<MyDbContext>(
sqlContainerConfig: options =>
{
// Local development configuration
options.Server = "localhost,1433";
options.Database = "MyDatabase";
options.UserId = "sa";
options.Password = "YourStrong@Password";
},
sqlAzureConfig: options =>
{
// Azure production configuration
options.Server = "myserver.database.windows.net";
options.Database = "MyDatabase";
// No password needed - uses Azure Identity
}
);
Environment-Aware Configuration
// The library automatically detects Azure environment
// Based on WEBSITE_SITE_NAME or IDENTITY_ENDPOINT environment variables
builder.Services.AddSqlDb<MyDbContext>(
sqlContainerConfig: localOptions =>
{
// Used when NOT in Azure
localOptions.Server = builder.Configuration["Sql:Server"]!;
localOptions.Database = builder.Configuration["Sql:Database"]!;
localOptions.UserId = builder.Configuration["Sql:UserId"]!;
localOptions.Password = builder.Configuration["Sql:Password"]!;
},
sqlAzureConfig: azureOptions =>
{
// Used when IN Azure
azureOptions.Server = builder.Configuration["Sql:AzureServer"]!;
azureOptions.Database = builder.Configuration["Sql:Database"]!;
}
);
Using DbContext Factory
public class MyService
{
private readonly IDbContextFactory<MyDbContext> _contextFactory;
public MyService(IDbContextFactory<MyDbContext> contextFactory)
{
_contextFactory = contextFactory;
}
public async Task<List<User>> GetUsersAsync()
{
// Create a new context instance
await using var context = await _contextFactory.CreateDbContextAsync();
return await context.Users.ToListAsync();
}
}
In-Memory Repository Pattern
// Define your repository
public class UserRepository : InMemoryRepository<string, User>
{
public async Task<Result<User>> GetByEmailAsync(string email)
{
var users = await GetAll();
if (!users.IsSuccess)
return Result.NotFound();
var user = users.Value.FirstOrDefault(u => u.Email == email);
return user is not null
? Result.Success(user)
: Result.NotFound();
}
}
// Use the repository
var repository = new UserRepository();
// Add
var user = new User { Id = "1", Name = "John", Email = "john@example.com" };
await repository.Add(user.Id, user);
// Get
var result = await repository.GetById("1");
if (result.IsSuccess)
{
Console.WriteLine($"Found: {result.Value.Name}");
}
// Update
user.Name = "John Updated";
await repository.Update(user.Id, user);
// Delete
await repository.Delete(user.Id);
// Get all
var allUsers = await repository.GetAll();
Configuration from appsettings.json
{
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=MyDb;User Id=sa;Password=Pass123;TrustServerCertificate=true"
},
"Sql": {
"Server": "localhost,1433",
"Database": "MyDatabase",
"UserId": "sa",
"Password": "YourStrong@Password",
"AzureServer": "myserver.database.windows.net"
}
}
Multiple DbContexts
// Register multiple database contexts
builder.Services.AddSqlDb<OrdersDbContext>(
builder.Configuration.GetConnectionString("OrdersDb")!
);
builder.Services.AddSqlDb<CustomersDbContext>(
builder.Configuration.GetConnectionString("CustomersDb")!
);
// Use in services
public class MyService
{
private readonly IDbContextFactory<OrdersDbContext> _ordersFactory;
private readonly IDbContextFactory<CustomersDbContext> _customersFactory;
public MyService(
IDbContextFactory<OrdersDbContext> ordersFactory,
IDbContextFactory<CustomersDbContext> customersFactory)
{
_ordersFactory = ordersFactory;
_customersFactory = customersFactory;
}
}
API Reference
ProjectExtensions
AddSqlDb<TDbContext> (with configurations)
public static IServiceCollection AddSqlDb<TDbContext>(
this IServiceCollection services,
Action<SqlLocalContainerOptions>? sqlContainerConfig,
Action<SqlAzureIdentityOptions>? sqlAzureConfig)
where TDbContext : DbContext
Registers a SQL database context with environment-aware configuration.
Parameters:
sqlContainerConfig: Configuration for local SQL Server containersqlAzureConfig: Configuration for Azure SQL with managed identity
Behavior:
- Detects Azure environment automatically
- Uses Azure config when in Azure, local config otherwise
- Registers both
IDbContextFactory<TDbContext>andIDesignTimeDbContextFactory<TDbContext>
AddSqlDb<TDbContext> (with connection string)
public static IServiceCollection AddSqlDb<TDbContext>(
this IServiceCollection services,
string connectionString)
where TDbContext : DbContext
Registers a SQL database context with an explicit connection string.
Parameters:
connectionString: The connection string to use
ISqlConnectionStringProvider
public interface ISqlConnectionStringProvider
{
string GetConnectionString();
}
Interface for providing database connection strings.
InMemoryRepository<TId, TItem>
Abstract base class for in-memory repositories using ConcurrentDictionary.
Add
public async Task<Result<TItem>> Add(TId id, TItem entity)
Adds a new entity to the repository.
GetById
public async Task<Result<TItem>> GetById(TId id)
Retrieves an entity by its ID. Returns Result.NotFound() if not found.
GetAll
public async Task<Result<IEnumerable<TItem>>> GetAll()
Retrieves all entities in the repository.
Update
public async Task<Result<TItem>> Update(TId id, TItem entity)
Updates an existing entity. Returns error if entity doesn't exist.
Delete
public async Task<Result> Delete(TId id)
Deletes an entity by ID. Returns Result.NotFound() if not found.
Store
public readonly ConcurrentDictionary<TId, TItem> Store
Direct access to the underlying concurrent dictionary for advanced scenarios.
SqlLocalContainerOptions
Configuration options for local SQL Server containers.
Properties:
Server: Server address (e.g., "localhost,1433")Database: Database nameUserId: User ID for authenticationPassword: Password for authenticationTrustServerCertificate: Whether to trust server certificate (typically true for local)
SqlAzureIdentityOptions
Configuration options for Azure SQL with managed identity.
Properties:
Server: Azure SQL server address (e.g., "myserver.database.windows.net")Database: Database name
Note: No password required - uses Azure Identity authentication.
Environment Detection
The library automatically detects Azure environments by checking:
var isAzure = !string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("WEBSITE_SITE_NAME")) ||
!string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("IDENTITY_ENDPOINT"));
Azure Indicators:
WEBSITE_SITE_NAME: Set in Azure App ServiceIDENTITY_ENDPOINT: Set when Azure Managed Identity is available
Azure Identity Authentication
When deployed to Azure, the library uses passwordless authentication:
- Managed Identity: Uses the app's managed identity
- Azure AD Authentication: No passwords stored in configuration
- Automatic Token Management: Tokens automatically refreshed
Azure SQL Configuration:
-- Grant permissions to managed identity
CREATE USER [your-app-name] FROM EXTERNAL PROVIDER;
ALTER ROLE db_datareader ADD MEMBER [your-app-name];
ALTER ROLE db_datawriter ADD MEMBER [your-app-name];
EF Core Migrations
The library supports EF Core design-time tools:
# Add migration
dotnet ef migrations add InitialCreate --project YourProject
# Update database
dotnet ef database update --project YourProject
The IDesignTimeDbContextFactory<TDbContext> registration enables migrations to work correctly.
Best Practices
Connection String Security
- Never commit passwords: Use user secrets or environment variables
- Use Azure Identity: Prefer managed identity over connection strings in Azure
- Rotate passwords: Regularly rotate local development passwords
DbContext Lifetime
- Use Factory Pattern: Always use
IDbContextFactory<T>for long-lived services - Dispose Contexts: Use
await usingto properly dispose contexts - Avoid Sharing: Don't share DbContext instances across requests
In-Memory Repository
- Testing Only: Use for unit tests and prototyping
- Not Thread-Safe Operations: While dictionary is thread-safe, your operations might not be
- No Persistence: Data lost when application stops
Configuration
- Environment-Specific: Use different configurations for dev, staging, production
- Validate Early: Ensure connection strings are valid at startup
- Use Configuration: Prefer configuration over hardcoded values
Testing
Using In-Memory Repository in Tests
[Fact]
public async Task Repository_AddAndRetrieve_Success()
{
// Arrange
var repository = new UserRepository();
var user = new User { Id = "1", Name = "Test User" };
// Act
await repository.Add(user.Id, user);
var result = await repository.GetById(user.Id);
// Assert
result.IsSuccess.Should().BeTrue();
result.Value.Name.Should().Be("Test User");
}
Using EF Core In-Memory Provider
[Fact]
public async Task DbContext_Query_Success()
{
// Arrange
var options = new DbContextOptionsBuilder<MyDbContext>()
.UseInMemoryDatabase(databaseName: "TestDb")
.Options;
await using var context = new MyDbContext(options);
context.Users.Add(new User { Name = "Test" });
await context.SaveChangesAsync();
// Act
var users = await context.Users.ToListAsync();
// Assert
users.Should().HaveCount(1);
}
Troubleshooting
Connection Failures
Issue: Cannot connect to SQL Server
Solutions:
- Verify server is running (Docker container, SQL Server instance)
- Check firewall rules
- Verify connection string format
- For Azure: Ensure managed identity has database permissions
Migration Failures
Issue: dotnet ef migrations fails
Solutions:
- Ensure design-time factory is registered
- Check connection string is accessible at design time
- Verify EF Core tools are installed:
dotnet tool install --global dotnet-ef
Azure Identity Issues
Issue: Authentication fails in Azure
Solutions:
- Verify managed identity is enabled in Azure portal
- Check SQL database permissions for managed identity
- Ensure
IDENTITY_ENDPOINTenvironment variable is set
Dependencies
- Ardalis.Result: For result pattern in repositories
- Ardalis.Result.FluentValidation: For validation integration
- Microsoft.EntityFrameworkCore.SqlServer: SQL Server provider for EF Core
- Microsoft.EntityFrameworkCore.Cosmos: Cosmos DB provider for EF Core
- Microsoft.EntityFrameworkCore.InMemory: In-memory provider for testing
Related Libraries
- Nabs.Launchpad.Core.SeedData: For seeding database with initial data
- Nabs.Launchpad.Core.Interfaces: For Orleans grain persistence
Target Framework
- .NET 10
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Ardalis.Result (>= 10.1.0)
- Ardalis.Result.FluentValidation (>= 10.1.0)
- Aspire.Microsoft.EntityFrameworkCore.SqlServer (>= 13.1.0)
- Microsoft.EntityFrameworkCore.Cosmos (>= 10.0.1)
- Microsoft.EntityFrameworkCore.InMemory (>= 10.0.1)
- Microsoft.EntityFrameworkCore.SqlServer (>= 10.0.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated | |
|---|---|---|---|
| 10.0.219 | 43 | 1/5/2026 | |
| 10.0.218 | 47 | 1/4/2026 | |
| 10.0.217 | 53 | 1/4/2026 | |
| 10.0.216 | 53 | 1/4/2026 | |
| 10.0.215 | 60 | 1/4/2026 | |
| 10.0.214 | 107 | 1/1/2026 | |
| 10.0.213 | 53 | 1/1/2026 | |
| 10.0.212 | 53 | 1/1/2026 | |
| 10.0.211 | 77 | 12/31/2025 | |
| 10.0.210 | 96 | 12/30/2025 | |
| 10.0.209 | 93 | 12/30/2025 | |
| 10.0.208 | 95 | 12/30/2025 | |
| 10.0.207 | 96 | 12/29/2025 | |
| 10.0.206 | 97 | 12/29/2025 | |
| 10.0.205 | 187 | 12/24/2025 | |
| 10.0.204 | 183 | 12/21/2025 | |
| 10.0.203 | 278 | 12/18/2025 | |
| 10.0.202 | 283 | 12/17/2025 | |
| 10.0.200 | 283 | 12/17/2025 | |
| 10.0.199 | 432 | 12/10/2025 | |
| 10.0.197 | 171 | 12/5/2025 | |
| 10.0.196 | 673 | 12/3/2025 | |
| 10.0.195 | 686 | 12/3/2025 | |
| 10.0.194 | 682 | 12/3/2025 | |
| 10.0.193 | 681 | 12/2/2025 | |
| 10.0.192 | 181 | 11/28/2025 | |
| 10.0.190 | 189 | 11/27/2025 | |
| 10.0.189 | 172 | 11/23/2025 | |
| 10.0.187 | 169 | 11/23/2025 | |
| 10.0.186 | 158 | 11/23/2025 | |
| 10.0.184 | 411 | 11/20/2025 | |
| 10.0.181-rc3 | 285 | 11/11/2025 | |
| 10.0.180 | 298 | 11/11/2025 | |
| 10.0.179-rc2 | 254 | 11/11/2025 | |
| 10.0.178-rc2 | 212 | 11/10/2025 | |
| 10.0.177-rc2 | 199 | 11/10/2025 | |
| 10.0.176-rc2 | 164 | 11/6/2025 | |
| 10.0.175-rc2 | 158 | 11/6/2025 | |
| 10.0.174-rc2 | 159 | 11/5/2025 | |
| 10.0.173-rc2 | 162 | 11/3/2025 | |
| 10.0.172-rc2 | 149 | 11/2/2025 | |
| 10.0.170-rc2 | 127 | 11/1/2025 | |
| 10.0.169-rc2 | 126 | 11/1/2025 | |
| 10.0.168-rc2 | 128 | 10/31/2025 | |
| 10.0.166-rc2 | 143 | 10/31/2025 | |
| 10.0.164-rc2 | 199 | 10/28/2025 | |
| 10.0.162-rc2 | 184 | 10/24/2025 | |
| 10.0.161 | 198 | 10/24/2025 | |
| 9.0.151 | 125 | 10/17/2025 | |
| 9.0.150 | 201 | 9/10/2025 | |
| 9.0.146 | 135 | 8/15/2025 | |
| 9.0.145 | 187 | 8/11/2025 | |
| 9.0.144 | 198 | 8/8/2025 | |
| 9.0.137 | 141 | 7/29/2025 | |
| 9.0.136 | 149 | 7/29/2025 | |
| 9.0.135 | 157 | 7/28/2025 | |
| 9.0.134 | 196 | 7/9/2025 | |
| 9.0.133 | 191 | 7/9/2025 | |
| 9.0.132 | 193 | 7/9/2025 | |
| 9.0.131 | 202 | 7/9/2025 | |
| 9.0.130 | 192 | 7/7/2025 |