NetEvolve.Pulse.SqlServer
0.7.1
Prefix Reserved
See the version list below for details.
dotnet add package NetEvolve.Pulse.SqlServer --version 0.7.1
NuGet\Install-Package NetEvolve.Pulse.SqlServer -Version 0.7.1
<PackageReference Include="NetEvolve.Pulse.SqlServer" Version="0.7.1" />
<PackageVersion Include="NetEvolve.Pulse.SqlServer" Version="0.7.1" />
<PackageReference Include="NetEvolve.Pulse.SqlServer" />
paket add NetEvolve.Pulse.SqlServer --version 0.7.1
#r "nuget: NetEvolve.Pulse.SqlServer, 0.7.1"
#:package NetEvolve.Pulse.SqlServer@0.7.1
#addin nuget:?package=NetEvolve.Pulse.SqlServer&version=0.7.1
#tool nuget:?package=NetEvolve.Pulse.SqlServer&version=0.7.1
NetEvolve.Pulse.SqlServer
SQL Server persistence provider for the Pulse outbox pattern using plain ADO.NET. Provides optimized T-SQL operations with proper transaction support and locking strategies for reliable event delivery in high-throughput scenarios.
Features
- Plain ADO.NET: No ORM overhead, direct SQL Server access via
Microsoft.Data.SqlClient - Transaction Support: Enlist outbox operations in existing
SqlTransactioninstances - Optimized Queries: Uses stored procedures with ROWLOCK/READPAST hints for concurrent access
- Configurable Schema: Customize schema and table names for multi-tenant scenarios
- Schema Interchangeability: Uses canonical schema compatible with Entity Framework provider
Installation
NuGet Package Manager
Install-Package NetEvolve.Pulse.SqlServer
.NET CLI
dotnet add package NetEvolve.Pulse.SqlServer
PackageReference
<PackageReference Include="NetEvolve.Pulse.SqlServer" Version="x.x.x" />
Database Setup
Before using this provider, execute the schema script to create the required database objects:
-- Execute the embedded script from the package
-- Located at: content/Scripts/OutboxMessage.sql
Or run via your deployment pipeline:
# Example using sqlcmd
sqlcmd -S your-server -d your-database -i OutboxMessage.sql
Schema Script Contents
The script creates:
[pulse]schema (configurable)[pulse].[OutboxMessage]table with optimized indexes- Stored procedures for CRUD operations with proper locking
Quick Start
using Microsoft.Extensions.DependencyInjection;
using NetEvolve.Pulse;
var services = new ServiceCollection();
services.AddPulse(config => config
.AddOutbox(
options => options.Schema = "pulse",
processorOptions => processorOptions.BatchSize = 100)
.AddSqlServerOutbox("Server=.;Database=MyDb;Integrated Security=true;TrustServerCertificate=true;")
);
Using Configuration
services.AddPulse(config => config
.AddOutbox()
.AddSqlServerOutbox(
sp => sp.GetRequiredService<IConfiguration>().GetConnectionString("Outbox")!,
options =>
{
options.Schema = "messaging";
options.TableName = "OutboxMessage";
})
);
Transaction Integration
Manual Transaction Enlistment
public class OrderService
{
private readonly string _connectionString;
private readonly IServiceProvider _serviceProvider;
public async Task CreateOrderAsync(CreateOrderRequest request, CancellationToken ct)
{
await using var connection = new SqlConnection(_connectionString);
await connection.OpenAsync(ct);
await using var transaction = connection.BeginTransaction();
try
{
// Business operation
await using var cmd = new SqlCommand("INSERT INTO [Order] ...", connection, transaction);
await cmd.ExecuteNonQueryAsync(ct);
// Store event in outbox (same transaction)
var outbox = new SqlServerEventOutbox(
connection,
_serviceProvider.GetRequiredService<IOptions<OutboxOptions>>(),
TimeProvider.System,
transaction);
await outbox.StoreAsync(new OrderCreatedEvent { OrderId = orderId }, ct);
await transaction.CommitAsync(ct);
}
catch
{
await transaction.RollbackAsync(ct);
throw;
}
}
}
Using IOutboxTransactionScope
public class UnitOfWork : IOutboxTransactionScope, IAsyncDisposable
{
private readonly SqlConnection _connection;
private SqlTransaction? _transaction;
public async Task BeginTransactionAsync(CancellationToken ct)
{
await _connection.OpenAsync(ct);
_transaction = _connection.BeginTransaction();
}
public object? GetCurrentTransaction() => _transaction;
public async Task CommitAsync(CancellationToken ct)
{
if (_transaction is not null)
{
await _transaction.CommitAsync(ct);
}
}
}
// Register in DI
services.AddScoped<IOutboxTransactionScope, UnitOfWork>();
Schema Customization
services.AddPulse(config => config
.AddOutbox(options =>
{
options.Schema = "myapp"; // Default: "pulse"
options.TableName = "Events"; // Default: "OutboxMessage"
})
.AddSqlServerOutbox(connectionString)
);
Remember to modify the SQL script accordingly when using custom schema/table names.
Performance Considerations
Indexing
The default schema includes optimized indexes for:
- Pending message polling (
Status,CreatedAt) - Completed message cleanup (
Status,ProcessedAt)
Stored Procedures
Operations use stored procedures with:
ROWLOCKfor row-level lockingREADPASTto skip locked rows during pollingSET NOCOUNT ONto reduce network traffic
Batch Processing
Configure batch size based on your throughput requirements:
.AddOutbox(processorOptions: options =>
{
options.BatchSize = 500; // Messages per poll
options.PollingInterval = TimeSpan.FromSeconds(1);
options.EnableBatchSending = true; // Use batch transport
})
Schema Interchangeability
This provider uses the canonical outbox schema, making it fully interchangeable with the Entity Framework provider:
- Development: Start with Entity Framework for rapid iteration
- Production: Switch to ADO.NET for maximum performance
- Mixed: Use both providers against the same database
// Both configurations work with the same database table
.AddSqlServerOutbox(connectionString)
// or
.AddEntityFrameworkOutbox<MyDbContext>()
Requirements
- .NET 8.0, .NET 9.0, or .NET 10.0
- SQL Server 2016 or later (or Azure SQL Database)
Microsoft.Data.SqlClientfor database connectivityMicrosoft.Extensions.Hostingfor the background processor
Related Packages
- NetEvolve.Pulse - Core mediator and outbox abstractions
- NetEvolve.Pulse.Dapr - Dapr pub/sub integration for event dispatch
- NetEvolve.Pulse.Extensibility - Core contracts and abstractions
- NetEvolve.Pulse.EntityFramework - Entity Framework persistence
- NetEvolve.Pulse.Polly - Polly v8 resilience policies integration
Documentation
For complete documentation, please visit the official documentation.
Contributing
Contributions are welcome! Please read the Contributing Guidelines before submitting a pull request.
Support
- Issues: Report bugs or request features on GitHub Issues
- Documentation: Read the full documentation at https://github.com/dailydevops/pulse
License
This project is licensed under the MIT License - see the LICENSE file for details.
Made with ❤️ by the NetEvolve Team
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. 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
- Microsoft.Data.SqlClient (>= 7.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.5)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.5)
- Microsoft.Extensions.Options (>= 10.0.5)
- NetEvolve.Pulse (>= 0.7.1)
-
net8.0
- Microsoft.Data.SqlClient (>= 7.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.5)
- Microsoft.Extensions.Hosting.Abstractions (>= 10.0.5)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.5)
- Microsoft.Extensions.Options (>= 10.0.5)
- NetEvolve.Pulse (>= 0.7.1)
-
net9.0
- Microsoft.Data.SqlClient (>= 7.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.5)
- Microsoft.Extensions.Hosting.Abstractions (>= 10.0.5)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.5)
- Microsoft.Extensions.Options (>= 10.0.5)
- NetEvolve.Pulse (>= 0.7.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.