SQL Server Provider
The SQL Server provider offers full relational database support with Dapper-based query execution, connection pooling, health checks, and built-in resilience.
Before You Start
- .NET 8.0+ (or .NET 9/10 for latest features)
- A SQL Server instance (local, Azure SQL, or AWS RDS)
- Familiarity with data access and IDb interface
Installation
dotnet add package Excalibur.Data.SqlServer
Dependencies: Excalibur.Data.Abstractions, Microsoft.Data.SqlClient, Dapper
Quick Start
using Microsoft.Extensions.DependencyInjection;
services.AddSqlServerPersistence("Server=localhost;Database=MyApp;Trusted_Connection=true;");
Registration Options
Basic Registration
// From connection string
services.AddSqlServerPersistence("Server=...;Database=...;");
// From configuration
services.AddSqlServerPersistence(configuration, sectionName: "SqlServerPersistence");
// With options callback
services.AddSqlServerPersistence(options =>
{
options.ConnectionString = "Server=...;Database=...;";
options.CommandTimeout = 60;
options.EnableConnectionResiliency = true;
});
Specialized Registration
// With automatic retry (Polly-based)
services.AddSqlServerPersistenceWithRetry(
connectionString,
maxRetryAttempts: 3,
retryDelayMilliseconds: 1000);
// With Always Encrypted column support
services.AddSqlServerPersistenceWithEncryption(
connectionString,
SqlConnectionColumnEncryptionSetting.Enabled);
// Read-only replica connection
services.AddSqlServerPersistenceReadOnly(connectionString);
// High-availability with failover support
services.AddSqlServerPersistenceHighAvailability(connectionString);
// With Change Data Capture integration
services.AddSqlServerPersistenceWithCdc(configuration, typeof(Program).Assembly);
Health Checks
services.AddHealthChecks()
.AddSqlServerPersistenceHealthCheck();
Transaction Scope
services.AddSqlServerTransactionScope(
IsolationLevel.ReadCommitted,
defaultTimeout: TimeSpan.FromSeconds(30));
Data Request Pattern
Define queries as reusable data request objects:
public class GetOrderByIdRequest : DataRequest<Order?>
{
public GetOrderByIdRequest(Guid orderId)
{
Command = new CommandDefinition(
"SELECT * FROM Orders WHERE Id = @Id",
new { Id = orderId });
}
}
// Execute via persistence provider
var order = await provider.ExecuteAsync(new GetOrderByIdRequest(orderId), cancellationToken);
Batch Operations
var requests = new[]
{
new InsertOrderRequest(order1),
new InsertOrderRequest(order2),
new InsertOrderRequest(order3)
};
await sqlProvider.ExecuteBatchInTransactionAsync(requests, scope, cancellationToken);
Configuration
{
"SqlServerPersistence": {
"ConnectionString": "Server=localhost;Database=MyApp;Trusted_Connection=true;",
"CommandTimeout": 30,
"EnableConnectionResiliency": true,
"MaxRetryAttempts": 3,
"RetryDelayMilliseconds": 1000,
"EnableDetailedLogging": false,
"EnableMetrics": true
}
}
Dead Letter Store
For messages that fail processing:
services.AddSqlServerDeadLetterStore(connectionString);
// Or with options
services.AddSqlServerDeadLetterStore(options =>
{
options.ConnectionString = connectionString;
options.TableName = "DeadLetters";
});
See Also
- Data Providers Overview — Architecture and core abstractions
- PostgreSQL Provider — Open-source SQL alternative
- Event Sourcing — SQL Server event store integration