Skip to content

🧩 Extensibility

One of the main goals of CoreSystem.Cache is to provide a caching framework that can evolve without requiring modifications to existing application code.

Rather than embedding infrastructure concerns directly into the cache service, the framework exposes extensibility points that allow new behaviors, storage providers, serializers, and other components to be added independently.

This document describes the available extension points and when to use each one.


Extension Points

The framework can be extended in several ways.

Extension Point Purpose
Cache Pipeline Add cross-cutting behaviors
Storage Providers Support new cache backends
Serializers Support additional serialization formats
Cache Key Generation Customize cache key creation
Metrics Publish custom telemetry
Dependency Injection Replace default implementations

Extending the Cache Pipeline

Every cache operation flows through the pipeline.

Application

↓

Cache Service

↓

Pipeline

↓

Storage

Because of this architecture, new behaviors can be introduced without modifying existing code.

Examples include:

  • Compression
  • Encryption
  • Auditing
  • Tracing
  • Validation
  • Custom Metrics

Creating a Custom Behavior

Implement the ICacheBehavior interface.

public sealed class CompressionBehavior
    : ICacheBehavior
{
    public async Task InvokeAsync(
        CacheContext context,
        CacheBehaviorDelegate next)
    {
        // Execute custom logic

        await next(context);

        // Execute additional logic
    }
}

Register the behavior.

services.AddSingleton<ICacheBehavior, CompressionBehavior>();

The new behavior automatically becomes part of the execution pipeline.


Creating a Custom Storage Provider

The framework supports multiple storage providers through the ICacheStorage abstraction.

ICacheStorage

├── MemoryStorage

├── RedisStorage

└── YourCustomStorage

Implement the storage interface.

public sealed class CosmosStorage
    : ICacheStorage
{
    // Implementation
}

Register it through dependency injection.

Once registered, the provider can participate in the storage resolution process.


Creating a Custom Serializer

Serialization is provider independent.

Implement the serializer interface.

public sealed class AvroSerializer
    : IPayloadSerializer
{
}

Then register the serializer.

services.AddSingleton<IPayloadSerializer, AvroSerializer>();

Applications can switch serialization strategies without changing cache code.


Replacing Default Services

Every core service is registered through dependency injection.

Applications can replace framework services with custom implementations when necessary.

Example:

services.Replace(
    ServiceDescriptor.Singleton<
        ICacheKeyBuilder,
        CustomCacheKeyBuilder>());

Custom Cache Key Generation

By default, cache keys are generated consistently across all providers.

Applications that require custom naming conventions can replace the key builder implementation.

Examples:

  • Tenant-aware keys
  • Region prefixes
  • Environment prefixes
  • Custom hashing

Adding Custom Metrics

The framework exposes OpenTelemetry metrics.

Additional metrics can be collected through custom pipeline behaviors.

Examples:

  • Business metrics
  • SLA measurements
  • Tenant metrics
  • Custom counters

Future Extension Points

The pipeline architecture enables additional capabilities without breaking the public API.

Examples include:

  • CompressionBehavior
  • EncryptionBehavior
  • ValidationBehavior
  • AuditBehavior
  • TracingBehavior
  • RateLimitingBehavior
  • ReplicationBehavior
  • WarmupBehavior

Design Principles

When extending the framework, follow these principles:

  • Single Responsibility Principle
  • Prefer composition over inheritance
  • Keep behaviors independent
  • Avoid coupling to storage implementations
  • Use dependency injection
  • Keep custom behaviors stateless whenever possible

Best Practices

✅ Create one behavior per concern.

✅ Do not modify existing framework behaviors.

✅ Prefer pipeline extensions over service replacement.

✅ Keep custom providers provider-independent.

✅ Preserve asynchronous execution.