AF.Umbraco.Redis.Connector
1.1.0
dotnet add package AF.Umbraco.Redis.Connector --version 1.1.0
NuGet\Install-Package AF.Umbraco.Redis.Connector -Version 1.1.0
<PackageReference Include="AF.Umbraco.Redis.Connector" Version="1.1.0" />
<PackageVersion Include="AF.Umbraco.Redis.Connector" Version="1.1.0" />
<PackageReference Include="AF.Umbraco.Redis.Connector" />
paket add AF.Umbraco.Redis.Connector --version 1.1.0
#r "nuget: AF.Umbraco.Redis.Connector, 1.1.0"
#:package AF.Umbraco.Redis.Connector@1.1.0
#addin nuget:?package=AF.Umbraco.Redis.Connector&version=1.1.0
#tool nuget:?package=AF.Umbraco.Redis.Connector&version=1.1.0
AF.Umbraco.Redis.Connector
Redis connector for Umbraco 15/16/17/18 on .NET 9/10.
This package wires Redis into Umbraco through an auto-discovered composer and includes:
IDistributedCachebacked by StackExchange.Redis, with a configurable key prefix per application.- ASP.NET Core Data Protection key-ring persistence in Redis, for load-balanced and containerized hosts.
- A dedicated Data Protection connection owned for the host lifetime and closed at shutdown.
- Startup Redis connectivity check that blocks app boot on connection or authentication failure.
- Option validation that fails fast on a missing connection string or blank required values.
- Programmatic StackExchange.Redis connection customization for TLS, retry, socket, and client options.
- Support for the current
AF.Umbraco.Redis.Connectorsection and the legacyAF:Umbraco:Redis:Connectorsection. - Optional package-hosted smoke endpoints (opt-in via
AF_SMOKE_TESTS=1, Development only).
Compatibility
- Package version:
1.1.0 - Umbraco CMS:
15.x,16.x,17.x,18.x - .NET:
9.0,10.0(Umbraco 17.x and 18.x require10.0) - Dependencies:
StackExchange.Redis,Microsoft.Extensions.Caching.StackExchangeRedis,Microsoft.AspNetCore.DataProtection.StackExchangeRedis
Version 1.1.0 supports Umbraco 15.x, 16.x, 17.x, and 18.x. Compatibility does not extend the upstream support lifetime: Umbraco 15.x and 16.x are EOL and are kept only as compatibility targets. Use the 17.x LTS or supported 18.x STS line in production. Review the Umbraco lifecycle before choosing a version.
Release 1.1.0
Version 1.1.0 adds Umbraco 18 compatibility, fixes an Umbraco 18 startup failure when smoke endpoints are enabled, and expands the test suite.
Host startup on Umbraco 18 aborted with a MissingMethodException when the smoke endpoints were enabled. The multi-argument UmbracoPipelineFilter constructor gained parameters in Umbraco 18, so binding to it at compile time failed at runtime on that major. The pipeline filter is now built through its single-argument constructor and property setters, which are stable across the whole supported range. Sites that never enable the smoke endpoints were not affected.
The test suite now covers what a host actually receives from the composer: distributed cache registration, startup validation, Data Protection wiring, the disabled state, legacy and current configuration precedence, and option validation failures. Regression tests pin the diagnostic endpoints to an explicit opt-in inside a Development environment, and cover non-GET verbs, exact path matching, probe-key cleanup after a failed write, and cancellation propagation on aborted requests.
An opt-in live suite runs the same code against a real Redis server, and scripts/run-all-host-smoke.sh boots every compatibility host in sequence. That multi-host layer is what surfaced the Umbraco 18 failure, because the package compiles against the floor of its supported range and a signature change in a later major fails only at runtime. A no-database smoke mode was added for environments without a disposable SQL Server database.
The test project moved from tests/ to src/AF.Umbraco.Redis.Connector.Tests, NuGet package output was standardized on _artifacts/nuget, and the CI workflow file was renamed to build-test-pack.yaml to match what it does.
An Umbraco 18.1.1 compatibility host targeting .NET 10 was added to the repository, and the package dependency range was widened to include Umbraco 18 while still excluding Umbraco 19. The four compatibility hosts adopted fixed, predictable ports derived from the Umbraco major, and every host received both a Kestrel and an IIS Express VS Code Run and Debug profile. NuGet vulnerability auditing was limited to dependencies referenced directly by each project, so advisories reaching the build only through the consuming Umbraco graph are no longer attributed to this package.
The Redis integration was hardened by preventing the smoke cache key from receiving InstanceName twice, returning HTTP 503 with an error payload when the write/read verification fails, removing temporary smoke keys after every diagnostic request, propagating request cancellation through smoke cache and response operations, and correcting the Umbraco SQL provider configuration key to umbracoDbDSN_ProviderName. The host smoke script was reworked so that it no longer writes credentials to appsettings.Local.json or leaves repository-local PID and log files.
The Data Protection Redis connection lifecycle is now explicit and disposable at host shutdown, connection-string parsing is strict while preserving retry-friendly AbortOnConnectFail=false behavior, and appsettings.Local.json loads only in Development. Microsoft Redis and StackExchange.Redis dependency floors were updated to their security patches within the existing major ranges. Smoke endpoint registration is limited to the Development environment behind an explicit opt-in, unattended smoke tests require an explicit acknowledgement before they may install a database, and unattended upgrades are no longer enabled anywhere, so no smoke run can migrate an existing schema.
Hosts can now register ordered Action<ConfigurationOptions> callbacks through ConfigureRedisConnection. The package applies them after parsing the connection string and setting its defaults, using a fresh configuration for the distributed cache, Data Protection, and startup connectivity validation connections.
Startup validation now has a positive, configurable StartupValidationTimeout with a 30-second default. The threshold covers the complete connection and PING sequence, while host shutdown cancellation interrupts either asynchronous wait without being reported as a Redis connectivity failure.
Test hosts and smoke CI
- Local compatibility hosts are included under
src/Umbraco.Cms.15.x,src/Umbraco.Cms.16.x,src/Umbraco.Cms.17.x, andsrc/Umbraco.Cms.18.x. - Host versions are Umbraco
15.4.4and16.5.1on .NET 9, and17.6.2and18.1.1on .NET 10. - Each host supports local overrides through
appsettings.Local.json. - VS Code Run and Debug configurations and their build tasks are available for every compatibility host.
| Host | HTTP | HTTPS |
|---|---|---|
| Umbraco 15 | http://localhost:5015 |
https://localhost:44375 |
| Umbraco 16 | http://localhost:5016 |
https://localhost:44376 |
| Umbraco 17 | http://localhost:5017 |
https://localhost:44377 |
| Umbraco 18 | http://localhost:5018 |
https://localhost:44378 |
Umbraco 18 uses Umbraco:CMS:Imaging:HMACSecretKey. The tracked appsettings.json contains an empty placeholder; set the real value only in the git-ignored appsettings.Local.json.
scripts/run-all-host-smoke.sh boots every compatibility host against a real Redis server and calls its diagnostic endpoints. Its default database mode boots a fully installed Umbraco runtime, with unattended install enabled and unattended upgrades disabled, against one dedicated database per major:
export REDIS_CONNECTION_STRING='provided-by-your-secret-store'
export UMBRACO_DB_DSN_15='provided-for-a-dedicated-smoke-database'
export UMBRACO_DB_DSN_16='provided-for-a-dedicated-smoke-database'
export UMBRACO_DB_DSN_17='provided-for-a-dedicated-smoke-database'
export UMBRACO_DB_DSN_18='provided-for-a-dedicated-smoke-database'
export UMBRACO_UNATTENDED_PASSWORD='provided-securely'
export AF_SMOKE_ALLOW_DATABASE_CHANGES=1
scripts/run-all-host-smoke.sh
Pass no-database for a faster check that needs no SQL Server: Umbraco stays in its install runtime state while the connector still composes, validates Redis at startup, and serves the smoke endpoints.
This is the layer that catches binary incompatibilities between Umbraco majors: the package compiles against the floor of its supported range, so an Umbraco API whose signature changed in a later major compiles cleanly and fails only at runtime on that major.
Build and test
Build the connector:
dotnet build src/AF.Umbraco.Redis.Connector/AF.Umbraco.Redis.Connector.csproj --no-restore
Run unit tests:
dotnet test src/AF.Umbraco.Redis.Connector.Tests/AF.Umbraco.Redis.Connector.Tests.csproj
Create the NuGet package:
dotnet pack src/AF.Umbraco.Redis.Connector/AF.Umbraco.Redis.Connector.csproj -c Release
Normal builds do not create a NuGet package. Run dotnet pack only during an explicitly approved
release after the changelog, package manifest, documentation, and marketplace metadata have been
aligned to the target release version.
The package is written to _artifacts/nuget, configured repository-wide through PackageOutputPath in Directory.Build.props. No command needs -o.
GitHub Actions compiles the Release binaries with ContinuousIntegrationBuild=true before the
test and manual pack steps. This normalizes build-time source paths for official CI artifacts;
local builds remain unchanged.
The suite includes regression coverage for composer registrations, disabled state, legacy and current configuration precedence, option validation failures, smoke endpoint opt-in gating, non-GET verbs and exact path matching, duplicated key prefixes, HTTP 503 on failed verification, temporary-key cleanup after a failed write, cancellation propagation on aborted requests, and the offline paths of the startup validator and the Data Protection connection owner.
An opt-in live suite runs the same code against a real Redis server and is skipped unless a connection string is provided:
export AF_REDIS_TEST_CONNECTION='provided-by-your-secret-store'
dotnet test src/AF.Umbraco.Redis.Connector.Tests/AF.Umbraco.Redis.Connector.Tests.csproj
It covers physical cache key prefixes, isolation between instance names, key expiration, Data Protection key-ring persistence and cross-provider unprotect, live startup connectivity, and the smoke endpoints. Point the variable at a disposable instance: each test generates a unique key prefix and deletes its own keys, but all tests share the target database.
Installation
Install from NuGet:
dotnet add package AF.Umbraco.Redis.Connector
Basic setup
1) No Program.cs changes required
The package wires services and middleware automatically via a composer.
You only need to configure appsettings*.json.
2) Configure appsettings*.json
Minimal setup:
{
"ConnectionStrings": {
"Redis": "redis.example.internal:6380,user=app,password=replace-from-secret-store,ssl=true,abortConnect=false"
}
}
Full setup:
{
"ConnectionStrings": {
"Redis": "redis.example.internal:6380,user=app,password=replace-from-secret-store,ssl=true,abortConnect=false"
},
"AF.Umbraco.Redis.Connector": {
"Enabled": true,
"ConnectionStringName": "Redis",
"InstanceName": "example:production:",
"DataProtectionKeysName": "example:production:_DataProtectionKeys",
"ValidateOnStartup": true,
"StartupValidationTimeout": "00:00:30"
}
}
The current section AF.Umbraco.Redis.Connector takes precedence over the legacy section AF:Umbraco:Redis:Connector when both exist. Keys defined only in the legacy section keep their legacy value.
For public/open-source repositories, keep placeholders in appsettings.Development.json and store real local values in appsettings.Local.json (git-ignored).
3) Redis secrets for local development
Keep Redis credentials out of the repository.
Credential precedence used by this project:
- Environment variables, for example
ConnectionStrings__Redis(set only in locallaunchSettings.jsonor in your shell) - The git-ignored
appsettings.Local.json, loaded only in Development appsettings.{Environment}.jsonandappsettings.json, which must contain placeholders only
In deployed environments, provide the connection string through a secret store or an environment-specific configuration provider. Prefer a dedicated Redis ACL user with the minimum required permissions, and enable TLS with ssl=true.
Configuration options
| Option | Type | Default | Purpose |
|---|---|---|---|
Enabled |
bool |
true |
Enables package registration. When false, nothing is registered. |
ConnectionStringName |
string |
Redis |
Selects ConnectionStrings:<name>. |
InstanceName |
string |
AF.Umbraco.Redis.Connector: |
Prefixes distributed-cache keys and sets the Data Protection application name. |
DataProtectionKeysName |
string |
AF.Umbraco.Redis.Connector:_DataProtectionKeys |
Redis key for the Data Protection key ring. Empty disables Redis key persistence. |
ValidateOnStartup |
bool |
true |
Blocks startup when Redis is missing, unreachable, or rejects authentication. |
StartupValidationTimeout |
TimeSpan |
00:00:30 |
Maximum duration of the complete startup connection and PING validation. |
Rules:
Enabled = falseshort-circuits the composer: no cache, no key-ring persistence, no startup validation, no smoke endpoints.ValidateOnStartup = falseskips the network check but does not make the connection string optional.StartupValidationTimeoutmust be greater than zero and applies to the complete connection-and-PINGoperation.- Use a distinct
InstanceNameper application and environment when several applications share one Redis instance.
See the configuration guide for environment-variable examples, precedence, ACL guidance, and production recommendations.
Programmatic connection customization
Advanced hosts can customize StackExchange.Redis options from an Umbraco composer:
using AF.Umbraco.Redis.Connector.Extensions;
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.DependencyInjection;
public sealed class RedisConnectionComposer : IComposer
{
public void Compose(IUmbracoBuilder builder)
{
builder.ConfigureRedisConnection(options =>
{
options.ClientName = "my-site-production";
options.ConnectRetry = 5;
options.SslHost = "redis.example.internal";
});
}
}
Multiple callbacks run in registration order. Each runs once for every package-owned connection configuration, after the connection string is parsed and AbortOnConnectFail=false is applied. Keep callbacks deterministic and side-effect free; an exception prevents the affected connection from being created and can block startup. Certificate-validation callbacks must perform real chain and host validation—never accept every certificate.
Data Protection key ring
When DataProtectionKeysName is non-empty, the ASP.NET Core Data Protection key ring is stored in Redis as a list under that key, and the application name is set from InstanceName.
- Every node sharing the same key and application name can decrypt what the others protected. This is what keeps authentication cookies valid across a load-balanced or containerized deployment.
- Redis persistence must be enabled if protected data must survive a Redis restart. Without it, the key ring is regenerated and users must sign in again.
- Changing
InstanceNameorDataProtectionKeysNameorphans the existing key ring. The new one is generated on the next start, and existing cookies stop validating.
Setup validation
- When Umbraco starts, the package validates the required option values and the selected connection string.
- With
ValidateOnStartupenabled, a hosted service parses the connection string strictly, connects, and executesPINGwithinStartupValidationTimeout. - If Redis is missing, unreachable, or rejects authentication, the failure is logged as critical and application startup is blocked, so the host never boots into a partially working state.
- Host shutdown cancellation interrupts waiting for both connection and
PINGcompletion.
Smoke endpoints (opt-in)
For local validation and CI checks you can enable built-in smoke endpoints by setting:
AF_SMOKE_TESTS=1
The host environment must also be Development. Both conditions are required.
Endpoints:
GET /smoke/healthreturns HTTP 200 with{ "status": "ok" }GET /smoke/redis/pingperforms a temporary cache write, read, and remove cycle, returning HTTP 200 on success and HTTP 503 on failure
These endpoints are disabled by default. They are diagnostics, not ASP.NET Core Health Checks, and must never be exposed as production monitoring endpoints: they accept unauthenticated requests and write to Redis.
Logging and alerts
- Package logs are emitted in English and include the
[AFURC]prefix for easy filtering. - Startup connectivity failures are logged as critical and block Umbraco startup.
- Successful validation logs the resolved endpoint and the measured ping, which is useful for confirming which Redis instance a host actually reached.
- Smoke endpoint failures and temporary-key cleanup failures are logged with the same prefix, as error and warning respectively.
Redis key layout
- Distributed cache entries:
{InstanceName}<logical key>, for exampleexample:production:umbraco-key. - Data Protection key ring: the exact value of
DataProtectionKeysName, stored as a Redis list. - Smoke diagnostics:
{InstanceName}smoke:<guid>, written and removed within the same request.
The prefix is applied by the cache provider, so logical keys used by Umbraco and by application code never include it.
Project documentation
For full technical documentation:
docs/README.mddocs/USER_MANUAL.mddocs/TECHNICAL_MANUAL.mddocs/API_REFERENCE.mddocs/ARCHITECTURE.mddocs/CONFIGURATION.mddocs/DEVELOPMENT.mddocs/TESTING.mddocs/OPERATIONS.mddocs/SECURITY.mddocs/TROUBLESHOOTING.mddocs/MAINTENANCE.mddocs/PROJECT_STRUCTURE.mddocs/CHANGELOG.md
Security checks
This repository runs automated secret scanning in GitHub Actions via Gitleaks (.github/workflows/secret-scan.yml).
Repository audits intentionally report direct dependencies only. Never include connection strings, credentials, or other secrets in issue reports.
Security advisory notice
This package does not introduce the known Umbraco advisory GHSA-69cg-w8vm-h229, but it can be installed on Umbraco versions that may still include it.
For production usage, always install the latest patched Umbraco release in your major/minor line.
Attribution request (non-binding)
If you fork or modify this project, please consider adding credits to:
- Project:
AF.Umbraco.Redis.Connector - Author:
Adriano Fabri - Url:
https://github.com/afabri73/AF.Umbraco.Redis.Connector
License
This project is licensed under MIT. See LICENSE.
Report defects through the GitHub issue tracker.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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.AspNetCore.DataProtection.StackExchangeRedis (>= 9.0.20 && < 11.0.0)
- Microsoft.Extensions.Caching.StackExchangeRedis (>= 9.0.20 && < 11.0.0)
- StackExchange.Redis (>= 2.8.58 && < 3.0.0)
- Umbraco.Cms.Web.Common (>= 15.0.0 && < 19.0.0)
-
net9.0
- Microsoft.AspNetCore.DataProtection.StackExchangeRedis (>= 9.0.20 && < 11.0.0)
- Microsoft.Extensions.Caching.StackExchangeRedis (>= 9.0.20 && < 11.0.0)
- StackExchange.Redis (>= 2.8.58 && < 3.0.0)
- Umbraco.Cms.Web.Common (>= 15.0.0 && < 19.0.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.1.0 - Adds Umbraco 18 support, programmatic Redis connection customization, a configurable startup validation timeout, expanded live and compatibility testing, deterministic CI builds, and Redis lifecycle and smoke diagnostic hardening.