PollyAzureKeyVault 1.0.1
See the version list below for details.
dotnet add package PollyAzureKeyVault --version 1.0.1
NuGet\Install-Package PollyAzureKeyVault -Version 1.0.1
<PackageReference Include="PollyAzureKeyVault" Version="1.0.1" />
<PackageVersion Include="PollyAzureKeyVault" Version="1.0.1" />
<PackageReference Include="PollyAzureKeyVault" />
paket add PollyAzureKeyVault --version 1.0.1
#r "nuget: PollyAzureKeyVault, 1.0.1"
#:package PollyAzureKeyVault@1.0.1
#addin nuget:?package=PollyAzureKeyVault&version=1.0.1
#tool nuget:?package=PollyAzureKeyVault&version=1.0.1
PollyAzureKeyVault
Polly v8 resilience for Azure.Security.KeyVault.Secrets — add retry, timeout, and circuit-breaker to any Azure Key Vault operation in two lines.
var secretClient = new SecretClient(new Uri("https://my-vault.vault.azure.net/"), credential);
var resilient = secretClient.WithPolly(pipeline => pipeline
.AddRetry(new RetryStrategyOptions
{
MaxRetryAttempts = 3,
Delay = TimeSpan.FromSeconds(2),
BackoffType = DelayBackoffType.Exponential,
UseJitter = true,
ShouldHandle = KeyVaultTransientErrors.IsTransient,
})
.AddTimeout(TimeSpan.FromSeconds(10)));
var secret = await resilient.GetSecretAsync("my-secret");
Why PollyAzureKeyVault?
Azure Key Vault is a hard dependency for most production apps — connection failures at startup or runtime cause outages. This library adds Polly v8 resilience without boilerplate:
| Problem | Solution |
|---|---|
| HTTP 429 throttling (Key Vault has strict rate limits) | Caught by KeyVaultTransientErrors.IsTransient |
| HTTP 503 during Key Vault maintenance / regional failover | Caught by KeyVaultTransientErrors.IsTransient |
| HTTP 504 gateway timeout | Caught by KeyVaultTransientErrors.IsTransient |
HttpRequestException network failure |
Caught by KeyVaultTransientErrors.IsTransient |
TaskCanceledException slow response |
Caught by KeyVaultTransientErrors.IsTransient |
| Cascading failures propagating to the rest of the app | Wrap with AddCircuitBreaker |
Installation
dotnet add package PollyAzureKeyVault
dotnet add package Polly.Core
Quick-start
1. Manual wiring
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
using Polly;
using Polly.Retry;
var credential = new DefaultAzureCredential();
var client = new SecretClient(new Uri("https://my-vault.vault.azure.net/"), credential);
var resilient = client.WithPolly(p => p
.AddRetry(new RetryStrategyOptions
{
MaxRetryAttempts = 3,
Delay = TimeSpan.FromSeconds(2),
BackoffType = DelayBackoffType.Exponential,
UseJitter = true,
ShouldHandle = KeyVaultTransientErrors.IsTransient,
}));
// Typed convenience methods
var secret = await resilient.GetSecretAsync("connection-string");
Console.WriteLine(secret.Value.Value);
2. Dependency injection
// Program.cs / Startup.cs
builder.Services.AddSingleton(new SecretClient(
new Uri("https://my-vault.vault.azure.net/"),
new DefaultAzureCredential()));
builder.Services.AddPollyAzureKeyVault(pipeline => pipeline
.AddRetry(new RetryStrategyOptions
{
MaxRetryAttempts = 3,
Delay = TimeSpan.FromSeconds(2),
BackoffType = DelayBackoffType.Exponential,
UseJitter = true,
ShouldHandle = KeyVaultTransientErrors.IsTransient,
})
.AddTimeout(TimeSpan.FromSeconds(10)));
// Inject ResilientSecretClient into your services
public class SecretsService(ResilientSecretClient client)
{
public async Task<string> GetConnectionStringAsync(CancellationToken ct) =>
(await client.GetSecretAsync("db-connection-string", cancellationToken: ct)).Value.Value;
}
3. With a URI shortcut (registers SecretClient automatically)
builder.Services.AddPollyAzureKeyVault(
new Uri("https://my-vault.vault.azure.net/"),
pipeline => pipeline
.AddRetry(new RetryStrategyOptions
{
MaxRetryAttempts = 5,
ShouldHandle = KeyVaultTransientErrors.IsTransient,
}));
Transient error reference
// Use in any Polly strategy:
ShouldHandle = KeyVaultTransientErrors.IsTransient
| Condition | Why it's transient |
|---|---|
RequestFailedException (HTTP 429) |
Key Vault rate limit — back off and retry |
RequestFailedException (HTTP 503) |
Vault maintenance or regional failover |
RequestFailedException (HTTP 504) |
Proxy or load balancer timed out |
HttpRequestException |
Network failure |
TaskCanceledException |
Request timed out in transit |
Handling only 429s with a longer back-off
.AddRetry(new RetryStrategyOptions
{
ShouldHandle = new PredicateBuilder()
.Handle<RequestFailedException>(ex => ex.Status == 429),
MaxRetryAttempts = 5,
Delay = TimeSpan.FromSeconds(10),
BackoffType = DelayBackoffType.Exponential,
})
Advanced pipelines
Full production pipeline
client.WithPolly(p => p
.AddTimeout(TimeSpan.FromSeconds(30))
.AddRetry(new RetryStrategyOptions
{
MaxRetryAttempts = 4,
Delay = TimeSpan.FromSeconds(2),
BackoffType = DelayBackoffType.Exponential,
UseJitter = true,
ShouldHandle = KeyVaultTransientErrors.IsTransient,
OnRetry = args =>
{
logger.LogWarning("Key Vault retry {Attempt} — {Exception}",
args.AttemptNumber, args.Outcome.Exception?.Message);
return ValueTask.CompletedTask;
},
})
.AddCircuitBreaker(new CircuitBreakerStrategyOptions
{
FailureRatio = 0.5,
SamplingDuration = TimeSpan.FromSeconds(30),
MinimumThroughput = 5,
BreakDuration = TimeSpan.FromSeconds(30),
ShouldHandle = KeyVaultTransientErrors.IsTransient,
}));
Arbitrary operations via ExecuteAsync
// Use ExecuteAsync<T> for any SecretClient method not covered by typed overloads
var props = await resilient.ExecuteAsync(
(c, ct) => c.GetDeletedSecretAsync("old-secret", ct));
API reference
ResilientSecretClient
| Member | Description |
|---|---|
Inner |
The underlying SecretClient |
GetSecretAsync(name, version?, ct) |
Retrieves a secret through the pipeline |
SetSecretAsync(name, value, ct) |
Creates or updates a secret through the pipeline |
StartDeleteSecretAsync(name, ct) |
Begins deletion through the pipeline |
ExecuteAsync<T>(operation, ct) |
Runs any SecretClient operation through the pipeline |
KeyVaultTransientErrors
| Member | Description |
|---|---|
IsTransient |
PredicateBuilder for 429/503/504 RequestFailedException, HttpRequestException, TaskCanceledException |
StatusCodes |
IReadOnlySet<int> — {429, 503, 504} |
Extension methods
| Method | Description |
|---|---|
client.WithPolly(pipeline) |
Wraps a SecretClient with a pre-built ResiliencePipeline |
client.WithPolly(configure) |
Builds a pipeline inline and wraps the client |
DI extensions
| Method | Description |
|---|---|
services.AddPollyAzureKeyVault(configure) |
Registers ResiliencePipeline + ResilientSecretClient (requires SecretClient already in DI) |
services.AddPollyAzureKeyVault(uri, configure) |
Registers SecretClient with DefaultAzureCredential, then pipeline + resilient client |
Target frameworks
| Framework | Supported |
|---|---|
| .NET 6 | ✅ |
| .NET 8 | ✅ |
| .NET 9 | ✅ |
Related packages
| Package | Description |
|---|---|
| PollyAzureBlob | Polly v8 for Azure Blob Storage |
| PollyAzureEventHub | Polly v8 for Azure Event Hubs |
| PollyAzureServiceBus | Polly v8 for Azure Service Bus |
| PollyCosmosDb | Polly v8 for Azure Cosmos DB |
| PollyElasticsearch | Polly v8 for Elastic.Clients.Elasticsearch |
| PollyRedis | Polly v8 for StackExchange.Redis |
| PollyEFCore | Polly v8 for Entity Framework Core |
| PollyDapper | Polly v8 for Dapper |
| PollyMongo | Polly v8 for MongoDB |
| PollyNpgsql | Polly v8 for Npgsql (PostgreSQL) |
| PollySqlClient | Polly v8 for Microsoft.Data.SqlClient |
| PollyGrpc | Polly v8 for gRPC |
| PollyRabbitMQ | Polly v8 for RabbitMQ |
| PollyKafka | Polly v8 for Confluent.Kafka |
| PollySignalR | Polly v8 for SignalR |
| PollyOpenAI | Polly v8 for OpenAI .NET SDK |
| PollyMediatR | Polly v8 for MediatR |
| PollyHealthChecks | Polly v8 for ASP.NET Core Health Checks |
| 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 | Polly v8 backoff helpers |
💼 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 © Justin Bannister
| 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
- Azure.Security.KeyVault.Secrets (>= 4.11.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.9)
- Polly.Core (>= 8.7.0)
-
net8.0
- Azure.Security.KeyVault.Secrets (>= 4.11.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.9)
- Polly.Core (>= 8.7.0)
-
net9.0
- Azure.Security.KeyVault.Secrets (>= 4.11.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.9)
- 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. ResilientSecretClient wraps SecretClient in a Polly v8 ResiliencePipeline. Includes KeyVaultTransientErrors helper with pre-built ShouldHandle predicate covering RequestFailedException (429, 503, 504) and transient network errors. Works with any Azure.Security.KeyVault.* client. Supports net6.0, net8.0, and net9.0.