PollyDapper 1.0.1
dotnet add package PollyDapper --version 1.0.1
NuGet\Install-Package PollyDapper -Version 1.0.1
<PackageReference Include="PollyDapper" Version="1.0.1" />
<PackageVersion Include="PollyDapper" Version="1.0.1" />
<PackageReference Include="PollyDapper" />
paket add PollyDapper --version 1.0.1
#r "nuget: PollyDapper, 1.0.1"
#:package PollyDapper@1.0.1
#addin nuget:?package=PollyDapper&version=1.0.1
#tool nuget:?package=PollyDapper&version=1.0.1
PollyDapper
Polly v8 resilience pipelines for Dapper — wrap QueryAsync, ExecuteAsync, and other Dapper calls with retry, timeout, circuit-breaker, and more using a single ResilientDbConnection decorator. Zero changes to your SQL.
var resilient = connection.WithPolly(pipeline =>
pipeline
.AddRetry(new RetryStrategyOptions
{
MaxRetryAttempts = 3,
Delay = TimeSpan.FromMilliseconds(200),
ShouldHandle = new PredicateBuilder().Handle<Exception>(),
})
.AddTimeout(TimeSpan.FromSeconds(5)));
var orders = await resilient.QueryAsync<Order>("SELECT * FROM Orders WHERE CustomerId = @Id", new { Id = id });
Every Dapper call is now automatically wrapped with retry + timeout — zero changes to existing SQL.
Why PollyDapper?
Dapper is intentionally minimal — it gives you no interception point for cross-cutting concerns like retry or timeout. PollyDapper adds that layer cleanly.
| Without PollyDapper | With PollyDapper |
|---|---|
| Write try/catch + retry loops around every query | One WithPolly(...) call |
Manually pass CancellationToken for timeouts |
Timeout managed by the pipeline |
| Duplicate retry logic across repositories | Single pipeline applied everywhere |
| Must touch every query to add resilience | Zero changes to existing SQL |
Installation
dotnet add package PollyDapper
Targets net6.0, net8.0, and net9.0.
Dependencies: Polly.Core 8.*, Dapper 2.*, Microsoft.Extensions.DependencyInjection.Abstractions 8.*
Quick start
1. Inline pipeline (ad-hoc usage)
using PollyDapper;
var resilient = connection.WithPolly(pipeline =>
pipeline.AddRetry(new RetryStrategyOptions
{
MaxRetryAttempts = 3,
Delay = TimeSpan.FromMilliseconds(200),
BackoffType = DelayBackoffType.Exponential,
ShouldHandle = new PredicateBuilder().Handle<Exception>(),
}));
var users = await resilient.QueryAsync<User>("SELECT * FROM Users");
2. Pre-built pipeline
var pipeline = new ResiliencePipelineBuilder()
.AddRetry(new RetryStrategyOptions { MaxRetryAttempts = 3 })
.AddTimeout(TimeSpan.FromSeconds(10))
.Build();
var resilient = connection.WithPolly(pipeline);
var count = await resilient.ExecuteScalarAsync<int>("SELECT COUNT(*) FROM Orders");
3. Dependency injection
// Program.cs
builder.Services.AddPollyDapper(pipeline =>
pipeline
.AddRetry(new RetryStrategyOptions { MaxRetryAttempts = 3 })
.AddTimeout(TimeSpan.FromSeconds(5)));
// Repository
public class OrderRepository(IDbConnection db, ResiliencePipeline pipeline)
{
public Task<IEnumerable<Order>> GetAllAsync() =>
db.WithPolly(pipeline).QueryAsync<Order>("SELECT * FROM Orders");
public Task<int> InsertAsync(Order order) =>
db.WithPolly(pipeline).ExecuteAsync(
"INSERT INTO Orders (CustomerId, Total) VALUES (@CustomerId, @Total)", order);
}
Supported methods
| Method | Description |
|---|---|
QueryAsync<T> |
Returns IEnumerable<T> |
QueryFirstAsync<T> |
First row, throws if empty |
QueryFirstOrDefaultAsync<T> |
First row or default |
QuerySingleAsync<T> |
Exactly one row, throws otherwise |
QuerySingleOrDefaultAsync<T> |
One row or default |
ExecuteAsync |
Rows affected |
ExecuteScalarAsync<T> |
First column of first row |
Pipeline order
Polly strategies are applied outer-to-inner (left-to-right). The recommended order is:
[Timeout] → [Retry] → [Circuit Breaker] → [Dapper]
pipeline
.AddTimeout(TimeSpan.FromSeconds(10)) // 1. Overall deadline
.AddRetry(retryOptions) // 2. Retry on failure
.AddCircuitBreaker(cbOptions) // 3. Open circuit if overloaded
ASP.NET Core example
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddScoped<IDbConnection>(_ =>
new SqlConnection(builder.Configuration.GetConnectionString("Default")));
builder.Services.AddPollyDapper(pipeline =>
pipeline
.AddRetry(new RetryStrategyOptions
{
MaxRetryAttempts = 3,
Delay = TimeSpan.FromMilliseconds(100),
BackoffType = DelayBackoffType.Exponential,
ShouldHandle = new PredicateBuilder()
.Handle<SqlException>(ex => ex.IsTransient),
})
.AddTimeout(TimeSpan.FromSeconds(30))
.AddCircuitBreaker(new CircuitBreakerStrategyOptions
{
FailureRatio = 0.5,
MinimumThroughput = 10,
SamplingDuration = TimeSpan.FromSeconds(30),
BreakDuration = TimeSpan.FromSeconds(15),
}));
Related packages
| Package | Downloads | Description |
|---|---|---|
| PollyEFCore | Polly v8 resilience for EF Core queries and SaveChanges | |
| PollySqlClient | Polly v8 resilience for SQL Server and Azure SQL with SqlServerTransientErrors predicate | |
| PollyMediatR | Polly v8 resilience pipelines for MediatR | |
| PollyHealthChecks | ASP.NET Core health checks for Polly v8 circuit breakers | |
| PollyOpenAI | Polly v8 resilience for OpenAI and Azure OpenAI — retry on 429, Retry-After, circuit breaker | |
| PollyRedis | Polly v8 resilience for StackExchange.Redis | |
| PollySignalR | Polly v8 exponential back-off reconnect policy for SignalR | |
| PollyElasticsearch | Polly v8 for Elastic.Clients.Elasticsearch | |
| PollyAzureKeyVault | Polly v8 for Azure Key Vault | |
| PollyAzureEventHub | Polly v8 for Azure Event Hubs | |
| PollySendGrid | Polly v8 for SendGrid | |
| PollyMassTransit | Polly v8 for MassTransit | |
| PollyAzureTableStorage | Polly v8 for Azure Table Storage | |
| PollyMailKit | MailKit SMTP email client | |
| PollyAzureQueueStorage | Azure Queue Storage QueueClient | |
| PollyHangfire | Hangfire IBackgroundJobClient | |
| PollyBackoff | Jitter, linear & custom backoff for Polly v8 retry | |
| PollyChaos | Fault & latency injection (Simmy for Polly v8) |
💼 Need .NET consulting?
The author of this package is available for consulting on Polly v8 resilience, Azure cloud architecture, and clean .NET design.
→ solidqualitysolutions.com · LinkedIn
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. 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 was computed. 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. |
-
net6.0
- Dapper (>= 2.1.79)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- Polly.Core (>= 8.7.0)
-
net8.0
- Dapper (>= 2.1.79)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- Polly.Core (>= 8.7.0)
-
net9.0
- Dapper (>= 2.1.79)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- Polly.Core (>= 8.7.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
1.0.1: Fix package icon (was showing an incorrect/placeholder image). 1.0.0: Initial release. ResilientDbConnection wraps IDbConnection Dapper calls in a Polly v8 ResiliencePipeline. Supports net6.0, net8.0, and net9.0.