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
                    
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="AF.Umbraco.Redis.Connector" Version="1.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="AF.Umbraco.Redis.Connector" Version="1.1.0" />
                    
Directory.Packages.props
<PackageReference Include="AF.Umbraco.Redis.Connector" />
                    
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 AF.Umbraco.Redis.Connector --version 1.1.0
                    
#r "nuget: AF.Umbraco.Redis.Connector, 1.1.0"
                    
#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 AF.Umbraco.Redis.Connector@1.1.0
                    
#: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=AF.Umbraco.Redis.Connector&version=1.1.0
                    
Install as a Cake Addin
#tool nuget:?package=AF.Umbraco.Redis.Connector&version=1.1.0
                    
Install as a Cake Tool

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:

  • IDistributedCache backed 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.Connector section and the legacy AF:Umbraco:Redis:Connector section.
  • 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 require 10.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, and src/Umbraco.Cms.18.x.
  • Host versions are Umbraco 15.4.4 and 16.5.1 on .NET 9, and 17.6.2 and 18.1.1 on .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:

  1. Environment variables, for example ConnectionStrings__Redis (set only in local launchSettings.json or in your shell)
  2. The git-ignored appsettings.Local.json, loaded only in Development
  3. appsettings.{Environment}.json and appsettings.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 = false short-circuits the composer: no cache, no key-ring persistence, no startup validation, no smoke endpoints.
  • ValidateOnStartup = false skips the network check but does not make the connection string optional.
  • StartupValidationTimeout must be greater than zero and applies to the complete connection-and-PING operation.
  • Use a distinct InstanceName per 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 InstanceName or DataProtectionKeysName orphans 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 ValidateOnStartup enabled, a hosted service parses the connection string strictly, connects, and executes PING within StartupValidationTimeout.
  • 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 PING completion.

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/health returns HTTP 200 with { "status": "ok" }
  • GET /smoke/redis/ping performs 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 example example: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.md
  • docs/USER_MANUAL.md
  • docs/TECHNICAL_MANUAL.md
  • docs/API_REFERENCE.md
  • docs/ARCHITECTURE.md
  • docs/CONFIGURATION.md
  • docs/DEVELOPMENT.md
  • docs/TESTING.md
  • docs/OPERATIONS.md
  • docs/SECURITY.md
  • docs/TROUBLESHOOTING.md
  • docs/MAINTENANCE.md
  • docs/PROJECT_STRUCTURE.md
  • docs/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 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. 
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.1.0 44 9/11/2026
1.0.0 162 3/4/2026

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.