PollyEFCore 1.0.1

dotnet add package PollyEFCore --version 1.0.1
                    
NuGet\Install-Package PollyEFCore -Version 1.0.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="PollyEFCore" Version="1.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="PollyEFCore" Version="1.0.1" />
                    
Directory.Packages.props
<PackageReference Include="PollyEFCore" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add PollyEFCore --version 1.0.1
                    
#r "nuget: PollyEFCore, 1.0.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package PollyEFCore@1.0.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=PollyEFCore&version=1.0.1
                    
Install as a Cake Addin
#tool nuget:?package=PollyEFCore&version=1.0.1
                    
Install as a Cake Tool

PollyEFCore

NuGet NuGet Downloads CI

Polly v8 resilience pipelines for Entity Framework Core — retry, timeout and circuit-breaker for every EF Core query and SaveChanges, for any database provider, with a single line of registration.

services.AddDbContext<AppDbContext>(options =>
    options
        .UseSqlServer(connectionString)
        .AddPollyResilience(pipeline =>
            pipeline.AddRetry(new RetryStrategyOptions
            {
                MaxRetryAttempts = 3,
                Delay = TimeSpan.FromMilliseconds(200),
                BackoffType = DelayBackoffType.Exponential,
                ShouldHandle = new PredicateBuilder().Handle<Exception>(),
            })));

Every query and SaveChangesAsync() is now automatically retried on transient failure — no changes to your DbContext, repositories, or handlers.


Why PollyEFCore?

EF Core's built-in EnableRetryOnFailure() only handles SQL Azure connection failures. PollyEFCore gives you the full power of Polly v8 for any EF Core provider.

Feature EnableRetryOnFailure() PollyEFCore
Provider support SQL Server / Azure SQL only Any (Postgres, MySQL, SQLite, CosmosDB…)
Retry strategy Fixed with jitter, hardcoded delays Exponential, linear, constant, custom
Timeout per command
Circuit breaker ✅ stop hammering a broken DB
Hedging (speculative queries)
Exception filter Hardcoded SQL error codes Any predicate — your codes, your rules
Observability ✅ via PollyOpenTelemetry

Installation

dotnet add package PollyEFCore

Targets net8.0 and net9.0 (requires EF Core 8+).

Dependencies: Polly.Core 8.*, Microsoft.EntityFrameworkCore.Relational 8.*


Quick start

One call on DbContextOptionsBuilderall commands wrapped automatically, no handler changes needed:

services.AddDbContext<AppDbContext>(options =>
    options
        .UseNpgsql(connectionString)           // any provider
        .AddPollyResilience(pipeline =>
            pipeline
                .AddRetry(new RetryStrategyOptions
                {
                    MaxRetryAttempts = 3,
                    Delay = TimeSpan.FromMilliseconds(100),
                    BackoffType = DelayBackoffType.Exponential,
                    ShouldHandle = new PredicateBuilder().Handle<Exception>(),
                })
                .AddTimeout(TimeSpan.FromSeconds(30))));

Use your DbContext exactly as normal — zero code changes required:

// Repository — completely unchanged
public async Task<List<Product>> GetProductsAsync(CancellationToken ct)
    => await _context.Products.Where(p => p.Active).ToListAsync(ct); // retried automatically

public async Task SaveAsync(Product product, CancellationToken ct)
{
    _context.Products.Add(product);
    await _context.SaveChangesAsync(ct); // retried automatically
}

Explicit wrapping (per-operation control)

Use ExecuteWithResilienceAsync when you need a different pipeline per operation, or when working inside an explicit transaction:

var products = await _context.Database.ExecuteWithResilienceAsync(
    _pipeline,
    ct => _context.Products.Where(p => p.Active).ToListAsync(ct),
    cancellationToken);

// Void overload
await _context.Database.ExecuteWithResilienceAsync(
    _pipeline,
    async ct =>
    {
        _context.Orders.Add(order);
        await _context.SaveChangesAsync(ct);
    },
    cancellationToken);

Provider examples

SQL Server — transient error filtering

Filter to known SQL Server transient error codes instead of catching all exceptions:

// Known SQL Server transient error numbers
private static readonly HashSet<int> SqlTransientErrors = new()
{
    -2,    // Timeout
    20,    // General network error
    64,    // Connection to SQL lost
    233,   // No process at the other end of the pipe
    10053, // Transport-level error
    10054, // Remote host forcibly closed
    10060, // Connection attempt failed
    40197, // Service encountered an error processing your request
    40501, // Service is currently busy
    40613, // Database is not currently available (Azure SQL)
    49918, // Cannot process request — not enough resources
};

services.AddDbContext<AppDbContext>(options =>
    options
        .UseSqlServer(connectionString)
        .AddPollyResilience(pipeline =>
            pipeline.AddRetry(new RetryStrategyOptions
            {
                MaxRetryAttempts = 3,
                Delay = TimeSpan.FromMilliseconds(200),
                BackoffType = DelayBackoffType.Exponential,
                ShouldHandle = new PredicateBuilder()
                    .Handle<SqlException>(ex => SqlTransientErrors.Contains(ex.Number))
                    .Handle<TimeoutException>(),
            })));

PostgreSQL (Npgsql)

services.AddDbContext<AppDbContext>(options =>
    options
        .UseNpgsql(connectionString)
        .AddPollyResilience(pipeline =>
            pipeline.AddRetry(new RetryStrategyOptions
            {
                MaxRetryAttempts = 3,
                Delay = TimeSpan.FromMilliseconds(100),
                BackoffType = DelayBackoffType.Exponential,
                ShouldHandle = new PredicateBuilder()
                    .Handle<NpgsqlException>(ex => ex.IsTransient)
                    .Handle<TimeoutException>(),
            })));

MySQL (Pomelo)

services.AddDbContext<AppDbContext>(options =>
    options
        .UseMySql(connectionString, ServerVersion.AutoDetect(connectionString))
        .AddPollyResilience(pipeline =>
            pipeline.AddRetry(new RetryStrategyOptions
            {
                MaxRetryAttempts = 3,
                Delay = TimeSpan.FromMilliseconds(200),
                ShouldHandle = new PredicateBuilder()
                    .Handle<MySqlException>(ex => ex.IsTransient)
                    .Handle<TimeoutException>(),
            })));

ASP.NET Core example with circuit-breaker

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<ShopDbContext>(options =>
    options
        .UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"))
        .AddPollyResilience(pipeline =>
            pipeline
                .AddRetry(new RetryStrategyOptions
                {
                    MaxRetryAttempts = 3,
                    Delay = TimeSpan.FromMilliseconds(200),
                    BackoffType = DelayBackoffType.Exponential,
                    ShouldHandle = new PredicateBuilder().Handle<Exception>(),
                })
                .AddTimeout(TimeSpan.FromSeconds(30))
                .AddCircuitBreaker(new CircuitBreakerStrategyOptions
                {
                    FailureRatio = 0.5,
                    MinimumThroughput = 10,
                    SamplingDuration = TimeSpan.FromSeconds(30),
                    BreakDuration = TimeSpan.FromSeconds(15),
                })));

Full-stack CQRS: PollyMediatR + PollyEFCore

Combine with PollyMediatR for end-to-end resilience in CQRS/MediatR apps — the MediatR layer retries the whole handler, and the EF Core layer retries individual commands:

// MediatR handler layer (outer) — retries the whole handler on failure
services.AddPollyMediatR(pipeline =>
    pipeline.AddRetry(new RetryStrategyOptions
    {
        MaxRetryAttempts = 2,
        ShouldHandle = new PredicateBuilder().Handle<TransientException>(),
    }));

// EF Core layer (inner) — retries individual SQL commands on transient DB errors
services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(cs).AddPollyResilience(pipeline =>
        pipeline.AddRetry(new RetryStrategyOptions
        {
            MaxRetryAttempts = 3,
            ShouldHandle = new PredicateBuilder().Handle<SqlException>(IsSqlTransient),
        })));

⚠️ Transaction note

The automatic interceptor wraps individual ADO.NET commands. When using explicit DbTransaction objects, configure your pipeline to handle only connection-level failures, or use ExecuteWithResilienceAsync for full unit-of-work retry control.


Package Downloads Description
PollyMediatR Downloads Polly v8 pipelines for MediatR request handlers
PollyBackoff Downloads Jitter, linear & custom backoff for Polly v8 retry
PollyChaos Downloads Fault & latency injection (Simmy for Polly v8)
PollyCaching Downloads Cache-aside resilience strategy for Polly v8
PollyBulkhead Downloads Bulkhead / concurrency limiter for Polly v8
PollyOpenTelemetry Downloads OpenTelemetry metrics & tracing for Polly v8

License

MIT

Product 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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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
1.0.1 61 6/23/2026
1.0.0 66 6/23/2026

1.0.1: Improved NuGet metadata and README with SQL Server transient error filtering, Npgsql/PostgreSQL examples, and PollyMediatR+PollyEFCore full-stack CQRS example.
1.0.0: Initial release. ResilienceDbCommandInterceptor wraps EF Core queries and SaveChanges with a Polly v8 ResiliencePipeline. AddPollyResilience() DI extension for DbContextOptionsBuilder. DatabaseFacade.ExecuteWithResilienceAsync() for explicit operation wrapping.